以下は、 Concurrent Programming on windows、Chapter 10 Page 528~529、c++ テンプレートからの抜粋です実装を再確認してください
T getValue(){
if (!m_pValue){
EnterCriticalSection(&m_crst);
if (! m_pValue){
T pValue = m_pFactory();
_WriteBarrier();
m_pValue = pValue;
}
LeaveCriticalSection(&m_crst);
}
_ReadBarrier();
return m_pValue;
}
著者の状態として:
_WriteBarrier は、オブジェクトをインスタンス化した後、m_pValue フィールドにそのオブジェクトへのポインターを書き込む前に見つかりました。これは、オブジェクトの初期化での書き込みが m_pValue 自体への書き込みを超えて遅延しないようにするために必要です。
_WriteBarrier はコンパイル バリアであるため、コンパイルが LeaveCriticalSection のセマンティクスを知っていると便利ではないと思います。コンパイルはおそらく pValue への書き込みを省略しますが、関数呼び出しの前に代入を移動するような最適化は行わないでください。そうしないと、プログラムのセマンティクスに違反します。LeaveCriticalSection には暗黙的なハードウェア フェンスがあると思います。したがって、m_pValue への割り当て前の書き込みはすべて同期されます。
一方、コンパイルが LeaveCriticalSection のセマンティクスを認識していない場合、コンパイルがクリティカル セクションから割り当てを移動するのを防ぐために、すべてのプラットフォームで _WriteBarrier が必要になります。
そして_ReadBarrierについて、著者は言った
同様に、m_value を返す直前に _ReadBarrier が必要です。これにより、getValue の呼び出し後のロードが、呼び出しの前に発生するように並べ替えられません。
まず、この関数がライブラリに含まれていて、ソース コードが利用できない場合、コンパイルはどのようにしてコンパイル バリアがあるかどうかを知るのでしょうか?
第二に、必要に応じて間違った場所に配置される可能性があります。取得フェンスを表現するには、EnterCriticalSection の直後に配置する必要があると思います。上で書いたことと同様に、コンパイルが EnterCriticalSection のセマンティクスを理解するかどうかに依存します。
また、著者は次のようにも述べています。
ただし、X86、Intel64、および AMD64 プロセッサではどちらのフェンスも必要ないことも指摘しておきます。IA64 のような弱いプロセッサが水を濁らせてしまったのは残念です
上記で分析したように、特定のプラットフォームでこれらのバリアが必要な場合は、すべてのプラットフォームでそれらが必要になります。これらのバリアはコンパイルバリアであるため、コンパイルが正しい最適化を実行できることを確認するだけです。一部の関数のセマンティクス。
間違っている場合は修正してください。
もう 1 つの質問ですが、msvc と gcc が同期セマンティクスを理解している関数を指摘する参照はありますか?
更新 1 : 回答によると (m_pValue はクリティカル セクションからアクセスされます)、ここからサンプル コードを実行すると、次のようになります。
- ここで著者が意味しているのは、コンパイル バリア以外のハードウェア フェンスであると思います。次のMSDNからの引用を参照してください。
- ハードウェアフェンスにも暗黙のコンパイルバリア(コンパイルの最適化を無効にする)があると思いますが、その逆はありません(ここを参照してください、cpuフェンスを使用しても並べ替えは表示されませんが、その逆はありません)
バリアはフェンスではありません。バリアはキャッシュ内のすべてに影響することに注意してください。フェンスは単一のキャッシュ ラインに影響します。
どうしても必要な場合を除き、バリアを追加しないでください。フェンスを使用するには、_Interlocked 組み込み関数のいずれかを選択できます。
著者が書いたように、「X86 Intel64 および AMD64 プロセッサではどちらのフェンスも必要ありません」。
まだ質問が残っています。コンパイルは、Enter/Leave クリティカル セクションの呼び出しのセマンティクスを理解していますか? そうでない場合は、次の回答のように最適化を行っている可能性があり、それが悪い動作を引き起こす可能性があります。
ありがとう