3

基本的に私は次のような状況にあります:

var tmp1 = new MyObject() { A = i, B = 2 };
// ** write barrier here??
this.Obj = tmp1;

別のスレッドは次のようなことを行うことができます:

var tmp = this.Obj;
// ** read barrier here?? 
use(tmp.A);

「Obj」のようなオブジェクトは 1 回だけ書き込まれ、その後複数のスレッドによって (複数回) 読み取られます。

Obj が両方のスレッドで null になることはありません。「this.Obj」の同期も気にしません。私が気にかけているのは、参照を読んだらtmp = Obj、その内容 (たとえばAB) も有効であるということです。

私の質問は次Thread.MemoryBarrier();のとおりです。上記のマークされた位置にメモリバリア(例:)が必要ですか、それとも常に暗黙的にOKですか?


人々はこの質問を嫌うようです。

私の質問は以下から来ています。私はメモリフェンスについて調べましたが、彼らは次のことを保証しています:(引用)

現在のスレッドを実行しているプロセッサは、MemoryBarrier の呼び出し前のメモリ アクセスが、MemoryBarrier の呼び出しに続くメモリ アクセスの後に実行されるように命令を並べ替えることができません。

コードを見ると、CPU / コンパイラがコードを書き直すことができる可能性があります。

var tmp1 = new MyObject();
tmp1.A = i;
tmp1.B = 2;
this.Obj = tmp1;

さらに悪いことに:

var tmp1 = new MyObject();
this.Obj = tmp1;
tmp1.A = i;
tmp1.B = 2;

別のスレッドが最後のケースを取得した場合、this.Objメモリから読み取ることができますがABデフォルト値は保持されます。

コンパイラが何を並べ替えることができるかだけの問題ではないことに注意してください。また、CPU が何を並べ替えることができるかの問題でもあります。

言い換えれば:(ありがとう@MattBurland)

tmp1 が割り当てられる前にオブジェクト初期化子が実行されることが保証されていますthis.Objか? または、メモリフェンスを使用してこれを手動で確認する必要がありますか?

4

1 に答える 1