0

グローバル カウンターがあり、ループ内でそれぞれ 100 回インクリメントする 2 つのスレッドがある場合、なぜ 200 以外の値を持つことができるのでしょうか? 変数へのアクセスが非アトミックであることがわかりません。

4

1 に答える 1

2

これは、ほとんどの環境では、メモリ位置のインクリメントはアトミック操作ではないためです。

イベントのシーケンスは次のようになります

  • コンパイラは、メモリ アドレス 0xABCD に値 0 を配置します。
  • スレッド 1 は 0xABCD をレジスタに読み取り、レジスタ値をインクリメントします。
  • スレッド 1 はスレッド 2 によって中断されます
  • スレッド 2 は、メモリ アドレス 0xABCD から値 0 をレジスタに読み取ります。
  • スレッド 2 は、レジスターの値をインクリメントします。
  • スレッド 2 はレジスタの値を 0xABCD に書き込みます。
  • スレッド 2 は 0xABCD から値 1 を読み取り、レジスタをインクリメントして、再度書き込みます。
  • スレッド 1 再開
  • スレッド 1 は、レジスタ 1 の値を 0xABCD に書き込み、スレッド 2 が以前にそこに書き込んだ値 2 を上書きします。

結果の一貫性を確保するには、インクリメント操作をアトミックにする必要があります。これは、多くの場合、インクリメント操作の周りにスレッド ロックを配置することによって行われます。たとえば、C# では次のようになります。

object mylock = new object();
...
lock (mylock) 
{ 
    myInt++;
}

あるいは、.NET 環境では、Interlocked.Increment を使用できます。

http://msdn.microsoft.com/en-us/library/dd78zt0c.aspx

他の環境にも同様の構造があります。

.NET 環境でのスレッド化について私がこれまでに遭遇した最高のリファレンスは次のとおりです (ただし、環境に関係なく読むのに役立ちます)。

http://www.albahari.com/threading/

于 2012-09-25T21:12:33.960 に答える