2

シングルトン パターンを持つクラスのインスタンスを取得するには、次の関数を使用します。

これはスケッチです

interface

uses SyncObjs;

type
  TMCriticalSection = class(TCriticalSection)
  private
    Dummy : array [0..95] of Byte;
  end;

var
  InstanceNumber : Integer;
  AObject: TObject;
  CriticalSection: TMCriticalSection;

function getInstance: TObject;

implementation

uses Windows;

function getInstance: TObject;
begin
   //I Want somehow use InterlockedCompareExchange instead of CriticalSession, for example

   if InterlockedCompareExchange(InstanceNumber, 1, 0) > 0 then
   begin
     Result := AObject;
   end
   else
   begin
      CriticalSection.Enter;
      try
        AObject := TObject.Create;
      finally
        CriticalSection.Leave;
      end;
      InterlockedIncrement(InstanceNumber);
      Result := AObject
   end;
end;

initialization
  CriticalSection := TMCriticalSection.Create;
  InstanceNumber := 0;

finalization;
  CriticalSection.Free;

end.

3 つの質問:

1- このデザインはスレッドセーフですか? 特にInterlockedExchangeパーツ付き。
2- InterlockedCompareExchange の使用方法は? 私がしようとしていることをすることは可能ですか?
3- この設計は、クリティカル セクションの範囲内にすべてのコードを含めるよりも優れていますか?

注意: 私のオブジェクトはスレッド セーフです。シリアル化する必要があるのは構造だけです!
これはコード全体ではなく、重要な部分、つまり getInstance 関数だけです。

編集

ある種のシングルトン オブジェクトを使用する必要があります
InstanceNumber の値がゼロの場合、InterlockedCompareExchange を使用して比較する方法はありますか?
And
1 - が 0 の場合にのみオブジェクトを作成し、それ以外の場合はインスタンスを返します。
2 - 値が 0 の場合: クリティカル セクションに入力します。オブジェクトを作成します。クリティカル セクションを残します。
3 - クリティカル セクションのスコープ内にすべてのコードを含めるのではなく、この方法で行う方がよいでしょうか?

4

2 に答える 2

4

あなたのデザインは機能しません。これは、何が機能するかを理解していなくてもわかりInterlockedCompareExchangeます。実際、 の意味に関係なくInterlockedCompareExchange、あなたのコードは壊れています。

これを確認するには、ifステートメントにgetInstance同時に到達する 2 つのスレッドを考えてみましょう。彼らが取る分岐の3つのオプションを考えてみましょう:

  1. どちらも 2 番目のブランチを選択します。次に、2 つのインスタンスを作成すると、コードはシングルトンを実装しなくなります。
  2. どちらも最初のブランチを選択します。その後、インスタンスを作成することはありません。
  3. 1 つは最初を選択し、もう 1 つは 2 番目を選択します。AObjectただし、最初のブランチにはロックがないため、そのルートを使用するスレッドは、他のスレッドが書き込む前に読み取ることができます。

個人的には、機能を実装する必要がある場合は、二重チェックのロックgetInstanceを使用します。

于 2013-05-17T13:00:38.157 に答える