質問

C#では、次のコード(から これ ページ)は、シングルトンクラスを安全な方法でゆっくりとインスタンス化するために使用できます。

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

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


この記事では、Javaでのダブルチェックロックに関する2つの問題についても言及しています。

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

したがって、C#のコードと上記の記事のJavaバージョンはほぼ同一に見えますが、C#バージョンのみが期待どおりに機能します。これらの2つの問題がダブルチェックロックのDelphiバージョンにも存在するかどうかは、追加の質問につながりますか?

役に立ちましたか?

解決

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;

詳細については、をご覧ください 私のオブジェクトをロックしてください...、お願いします! から アレン・バウアー. 。実際、担当者。私はこれから集まってアレンに行くはずです。

他のヒント

もちろん、それを覚えておく価値は常にあります ダブルチェックロックが壊れています. 。この問題は、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;

これは質問に対する答えではないことに気付きましたが、コメントにはまったく当てはまりませんでした!

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top