Delphiで「ダブルチェックロック」をどのように実装すべきですか?
-
11-10-2019 - |
質問
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;
これは質問に対する答えではないことに気付きましたが、コメントにはまったく当てはまりませんでした!
所属していません StackOverflow