2015-09-28 11 views
6

MEFのソースコードを参照すると、この部分が見つかりました。 誰かがロック内になぜMemoryBarrierが必要なのか説明できますか?ここでThread.MemoryBarrierが使用されるのはなぜですか?

全体の方法は次のとおりです。

public void SatisfyImportsOnce(ComposablePart part) 
{ 
    this.ThrowIfDisposed(); 

    if (this._importEngine == null) 
    { 
     ImportEngine importEngine = new ImportEngine(this, this._compositionOptions); 

     lock(this._lock) 
     { 
      if (this._importEngine == null) 
      { 
       Thread.MemoryBarrier(); 
       this._importEngine = importEngine; 
       importEngine = null; 
      } 
     } 
     if(importEngine != null) 
     { 
      importEngine.Dispose(); 
     } 
    } 
    this._importEngine.SatisfyImportsOnce(part); 
} 
+0

に割り当てられた前に、この場合の

また、メモリバリアがimportEngine 新鮮 garanteeを提供*時々、ロックが十分 –

+0

ではありませんそれは多くのコンテキストを知らなくても、この質問に答えることは不可能だと*ようです。 –

+3

メモリモデルが脆弱なプロセッサではFUDですが、マイクロソフトのプログラマの中には、おそらくItaniumを習得する必要から回復しないものがあります。これは、_importEngine参照を使用するときに、完全に構築されたオブジェクトを別のスレッドが監視できることを保証します。弱いプロセッサでは、オブジェクトフィールドが書き込まれる前に参照がメモリに書き込まれ、別のスレッドが初期化されていないフィールド値を見ることができます。 .NET 2.0以降では必要ありません。ロックはすでにメモリの壁を意味するため、ここでは必ずしも必要ではありません。 –

答えて

1

Thread.MemoryBarrierは、コードの最適化のために並べ替え任意の指示ジッタ/コンパイラを防ぐことができます。彼はサイスTreading in C#, by Joe Albahari本の中で

  • コンパイラ、CLR、またはCPUは、効率を改善するために、あなたのプログラムの指示の順序を変更することがあります。
  • コンパイラ、CLR、またはCPUは、変数への代入がほかのスレッドからすぐには見えないようなキャッシング最適化を導入する可能性があります。

この例では、importEngineまたは_importEngineの値がキャッシュされている可能性があります。すべてのスレッドに変更がすぐに通知されることが非常に重要です。それは_importEngine

+1

しかし、ロックはメモリバリヤーを意味します。 'importEngine'と' _importEngine'のどちらもロックの中にキャッシュすることはできません。 (他の人が 'this._lock'をロックせずに' _importEngine'に書き込みをしない限り)。 –

+0

@ScottChamberlainあなたは正しいですか?それで、私はMemoryBarrierがこの場合に使用されていると思うのですが、_lockを使わずに_importEngingeに書き込む他のスレッドがあるかもしれません。 –

+2

CLI(CLRの標準化されたバージョン)では、ダブルチェックされたロックイディオムの基本ヌルチェックは不十分です。 CLIのメモリモデルでは、変数がvolatileまたは明示的なバリアを使用する必要があります。 CLRはより強力なメモリモデルを持ち、揮発性も障壁も不要です。このコードの作成者はCLRの余分な保証を知らなかったかもしれませんし、Jon Skeet氏がCLRに依存しない方が好きかもしれません。バリアは、一度初期化され、同期されると、後の呼び出しがロックの内容を完全にスキップするため、コストが限られています。 –

関連する問題