2013-02-28 7 views
5

なぜこの部分のコードcompleteがキャッシュされていますか?可変キャッシング

static void Main() 
{ 
    bool complete = false; 
    var t = new Thread (() => 
    { 
    bool toggle = false; 
    while (!complete) toggle = !toggle; 
    }); 
    t.Start(); 
    Thread.Sleep (1000); 
    complete = true; 
    t.Join();  // Blocks indefinitely 
} 

しかし、この部分ではありませんか?

static void Main() 
{ 
    bool complete = false; 
    bool toggle = false; 
    var t = new Thread (() => 
    { 
    while (!complete) toggle = !toggle; 
    }); 
    t.Start(); 
    Thread.Sleep (1000); 
    complete = true; 
    t.Join(); 
} 

答えて

0

私の場合は完全に両方のサンプルが、あなたは、ラムダ/デリゲートが問題になる可能性が異なるコンパイラで異なってコンパイルすることができます。

代理人が変更されたクロージャにアクセスしているため、問題が発生している可能性があります。 Jon Skeetが提供している答え、Access to Modified Closureを見てください。これはまったく同じ問題ではありませんが、ここで説明した理由はあなたの場合でも同様です。

3

スレッド間で非同期データ共有を行っています。サイレンは今すぐ消えるはずです。

メモリモデルを理解しているので、JITはcompleteを一度読んでレジスタに格納することができます。そのため、Mainからの更新は表示されません。

これを修正するには、最も簡単な方法は、アクセスを回避するためにロックをcompleteにラップすることです。 Thread.VolatileReadThread.VolatileWriteを使用することもできます。

+0

固定に関する問題ではありません。 **なぜ**最初のスニペットで 'compare'がキャッシュされますが、2番目にはありませんか? –

+0

私はその点を逃しました。これは、2番目のスニペットのトグルがヒープで、1番目がローカル変数の書き込みであるためです。ヒープストアは特定の並べ替えを防ぎます。彼らは時々それらの間に "キャッシング"を防ぐ。どちらかは、x86/.NETメモリモデルによって正式に保証されるか、JITオプティマイザのクォーク/プロパティです。 – usr

3

上記のようにすべてのアーキテクチャでキャッシュが行われることや、プログラムの複数の実行で常に上記のようにキャッシュされることを確認しないでください。

である可能性があります。なぜなら、2番目のケースではラムダがクロージャを変更していますが、最初はクロージャにのみアクセスしているからです。もちろん、これは唯一の野生の推測です。

さらに重要な

しかし、はキャッシュ時行われますについての保証は時にスレッドがない使用キャッシュされた値意志メモリ境界のみを指定し、存在しません。

ボトムラインでは、キャッシュを使用することはできません。

関連する問題