2012-05-10 11 views
3

基本的な算術演算はスレッドセーフですか?C#の基本的な算術演算はアトミックです

例えば、異なるスレッドから変更されるグローバル変数に++操作がある場合、そのスレッドをロックする必要がありますか?例

void MyThread() // can have many running instances 
{ 
    aGlobal++; 
} 

またはそれが

void MyThread() 
{ 
    lock(lockerObj) 
    { 
     aGlobal++; 
    } 
} 
+4

これは排他的な算術演算ではありません...変数への書き込みもあります! 'a + a'は' a = a + a'とは異なるものです。あなたは 'Interlocked.Increment'やalikesを使う必要があります! –

答えて

8

The spec非常によく、それを合計する必要がありますについては

。 5.5節、 "変数の参照の不可分性":

を読み込み、次のデータ型の書き込みはアトミックです:BOOL、CHAR、 バイト、sbyte、短い、USHORT、UINT、int型、float型、および参照型。 では、元の型のの列挙型の読み書きもアトミックです。 long、ulong、double、およびdecimalを含む の型およびユーザー定義の 型の読み込みと書き込みは、アトミックであることが保証されていません。ライブラリ はその目的のために設計された機能のほかに、インクリメントまたはデクリメントの場合のように、アトミック のリード・モディファイ・ライトの保証はありません。

結論:

  • 独立した読み取り/書き込みが
  • 読む/ である(例えばi++など)/書き込みを変更することはありません原子
  • あなた原子(だけで一部のデータ型のため)ですInterlockedクラスメソッドを使用して、アトミック性が保証されていない場合に使用できます。

Interlockedの機能が十分でない場合は、Monitor.Enter(コンパイラもlockステートメントで公開されます)など、同期プリミティブを使用する以外のオプションはありません。

2

を独立して読み書きします。は、ほとんどのタイプ(長いタイプではなく、通常は64ビット+)にアトミックです。しかし、あなたが望むのは、原子的に読み取り、変更し、次に書くことです - これは確かにではなく、アトミックです。

値をインクリメントする必要がある場合は、IncrementDecrementという静的なアクションを持つSystem.Threading.Interlockedクラスがあります。

さらに複雑な合計を行う必要がある場合は、lockまたは別の構成を使用した同期が唯一の方法です。それはメッセージングシステムのように不変なものにするため、共有データアクセスの問題は発生しませんが、これは通常、初期設定されていない限り達成できません。

0

どちらも... System.Threading.Interlocked.Increment(ref int location)に行ってはいけません。これはロックされておらず、プロセッサが確実に所望の順序でリードとライト(命令 - アトミックな命令)を確実に実行するのに対し、System.Threading.Interlocked.Incrementを使用しないと命令に命令を並べ替える機会が与えられる。

大量の操作を行っている可能性があるため、スレッジハンマーを使用している場合や他の可能性がない場合はlockを使用することもできますが、これらのシナリオでも、代わりにSystem.Threading.ReaderWriterLockSlimに行きます。

btw-a nice read

関連する問題