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();  
}
4

3 に答える 3

3

上記のようにすべてのアーキテクチャでキャッシュが発生するかどうか、またはプログラムの複数回の実行で常に上記のように発生するかどうかを確認しないでください。

2 番目のケースではラムダがクロージャを変更しているのに対し、最初のケースではクロージャにアクセスしているだけである可能性があります。もちろん、これは勝手な推測にすぎません。

さらに重要なのは、キャッシュいつ実行されるかについての保証はなく、メモリ境界は、スレッドがキャッシュされた value をいつ使用しないかを指定するだけです。

要するに、キャッシュが発生することに依存することはできません。

于 2013-02-28T23:50:48.510 に答える
3

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

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

これを修正する最も簡単な方法は、 へのアクセスをロックでラップすることcompleteです。Thread.VolatileReadとを使用することもできますThread.VolatileWrite

于 2013-02-28T23:45:06.877 に答える
0

私の場合、両方のサンプルが完了しましたが、ラムダ/デリゲートは異なるコンパイラで異なる方法でコンパイルされる可能性があり、これが問題になる可能性があります。

デリゲートは変更されたクロージャにアクセスしています。これは多くの問題を引き起こす可能性があり、明らかに問題を見つけました。ここで Jon Skeet が提供する回答Access to Modified Closureを見てください。まったく同じ問題ではありませんが、ここで説明する理由はあなたの場合にも当てはまります。

于 2013-02-28T22:59:18.963 に答える