C++ と二重チェック ロックの危険性には、著者が提案するパターンを正しく実装するための persudo コードがあります。下記参照、
Singleton* Singleton::instance () {
Singleton* tmp = pInstance;
... // insert memory barrier (1)
if (tmp == 0) {
Lock lock;
tmp = pInstance;
if (tmp == 0) {
tmp = new Singleton;
... // insert memory barrier (2)
pInstance = tmp;
}
}
return tmp;
}
最初のメモリバリアを return ステートメントのすぐ上に移動できるかどうか疑問に思っていますか?
編集:別の質問:リンクされた記事で、vidstigeが引用したように
技術的には、完全な双方向バリアは必要ありません。最初のバリアは、(別のスレッドによる) Singleton の構造の下方への移行を防止する必要があります。2 番目のバリアは、pInstance の初期化の上方移行を防止する必要があります。これらは「取得」および「解放」操作と呼ばれ、区別を行うハードウェア (Itainum など) 上の完全なバリアよりも優れたパフォーマンスをもたらす可能性があります。
2 番目のバリアは双方向である必要はないと言われていますが、pInstance への割り当てがそのバリアの前に移動されないようにするにはどうすればよいでしょうか? 最初のバリアは上向きの移行を防ぐことができますが、別のスレッドはまだ初期化されていないメンバーを見る機会があります。
編集:最初の障壁の目的をほぼ理解していると思います。sonicoderが指摘したように、if が true を返すと、分岐予測により tmp が NULL になる可能性があります。この問題を回避するには、if を読み取る前に tmp を読み取らないようにするための取得バリアが必要です。
最初のバリアは 2 番目のバリアとペアになって同期関係を実現するため、下に移動できます。
編集:この質問に興味がある人は、memory-barriers.txtを読むことを強くお勧めします。