5

C# では、次のコード (このページから) を使用して、スレッド セーフな方法でシングルトン クラスを遅延インスタンス化できます。

  class Foo {
        private volatile Helper helper = null;
        public Helper getHelper() {
            if (helper == null) {
                lock(this) {
                    if (helper == null)
                        helper = new Helper();
                }
            }
            return helper;
        }
    }

同等のスレッドセーフな Delphi コードは何ですか?


この記事では、Java の Double Checked Locking に関する 2 つの問題についても言及しています。

  • ヘルパー参照が新しく作成されたオブジェクトを指すように作成される前に、新しいオブジェクトが構築される可能性があります。つまり、2 つのオブジェクトが作成されます。
  • オブジェクトがまだ作成されている間に、ヘルパー参照がメモリのブロックを指すように作成される可能性があります。つまり、不完全なオブジェクトへの参照が返されます。

そのため、前述の記事の C# と Java バージョンのコードはほとんど同じように見えますが、C# バージョンだけが期待どおりに機能します。これら 2 つの問題が Delphi バージョンの Double-Checked Locking にも存在する場合、追加の質問につながるのはどれですか?

4

2 に答える 2

7

System.TMonitor を使用して、スレッド セーフな方法でオブジェクト インスタンスをロックします。

function TFoo.GetHelper(): THelper;
begin
  if not Assigned(FHelper) then
  begin
    System.MonitorEnter(Self);
    try
      if not Assigned(FHelper) then
        FHelper := THelper.Create();
    finally
      System.MonitorExit(Self);
    end;
  end;
  Result := FHelper;
end;

詳細については、Lock my object... を参照してください。アレン・バウアーより。実は担当者。私はアレンに行くべきであることから収集します。

于 2010-12-17T22:24:59.250 に答える
2

もちろん、Double-Checked Locking は Brokenであることを常に覚えておく価値があります。この問題は x86 メモリ モデルには当てはまらないことが判明しましたが、将来のために常に念頭に置いておく価値があります。この問題に悩まされているメモリ モデルを備えたプラットフォームで動作する Delphi バージョンがいずれリリースされると確信しています。

Embarcadero は、インターロックされた比較/交換を備えたこのパターンのロックなしバージョンの使用を開始しました。例えば:

class function TEncoding.GetUnicode: TEncoding;
var
  LEncoding: TEncoding;
begin
  if FUnicodeEncoding = nil then
  begin
    LEncoding := TUnicodeEncoding.Create;
    if InterlockedCompareExchangePointer(Pointer(FUnicodeEncoding), LEncoding, nil) <> nil then
      LEncoding.Free;
  end;
  Result := FUnicodeEncoding;
end;

これは質問への回答ではないことは承知していますが、コメントに収まりませんでした!

于 2010-12-18T11:06:20.743 に答える