基本的な算術演算はスレッドセーフですか?
たとえば、++異なるスレッドから変更されるグローバル変数に対する操作がある場合、その周りをロックする必要がありますか?
例えば
void MyThread() // can have many running instances
{
aGlobal++;
}
またはそれはする必要があります
void MyThread()
{
lock( lockerObj)
{
aGlobal++;
}
}
基本的な算術演算はスレッドセーフですか?
たとえば、++異なるスレッドから変更されるグローバル変数に対する操作がある場合、その周りをロックする必要がありますか?
例えば
void MyThread() // can have many running instances
{
aGlobal++;
}
またはそれはする必要があります
void MyThread()
{
lock( lockerObj)
{
aGlobal++;
}
}
スペックはそれを非常にうまくまとめています。セクション5.5「変数参照のアトミシティ」:
次のデータ型の読み取りと書き込みはアトミックです:bool、char、byte、sbyte、short、ushort、uint、int、float、および参照型。さらに、前のリストの基になる型を持つ列挙型の読み取りと書き込みもアトミックです。long、ulong、double、decimalなどの他のタイプの読み取りと書き込み、およびユーザー定義タイプは、アトミックであることが保証されていません。その目的のために設計されたライブラリ関数を除いて、インクリメントまたはデクリメントの場合など、アトミックな読み取り-変更-書き込みの保証はありません。
結論:
i++)は決してアトミックではありませんInterlockedまだ保証されていない場合は、クラスメソッドを使用して原子性を実現できます機能が十分でない場合Interlockedは、同期プリミティブを使用する以外に選択肢はありませんMonitor.Enter(コンパイラーもlockステートメントを通じて公開します)。
読み取りと書き込みは、ほとんどのタイプで独立してアトミックです(長いタイプではなく、通常は64ビット以上)。しかし、必要なのは、アトミックに読み取り、変更、および書き込みを行うことです。これは、アトミックではありません。
値をインクリメントする必要がある場合は、System.Threading.Interlocked静的アクションIncrementとDecrementアクションを持つクラスがあります。
より複雑な合計を行う必要がある場合lockは、または別の構成を使用した同期が唯一の方法です。または、メッセージングシステムのように物事を不変にして、共有データアクセスの問題が発生しないようにしますが、事前に設計されていない限り、これは通常は達成できません。
System.Threading.Interlocked.Increment(ref int location)どちらでもない...あなたは代わりに行くべきです。これは、プロセッサが読み取りと書き込み(アトミックである命令)を希望どおりの順序で実行することを保証するため、ロックフリーですが、使用しないSystem.Threading.Interlocked.Incrementと、プロセッサが命令を並べ替える機会が提供されます。
スレッジハンマーを実行する(または、大量の操作を実行する可能性があるため、他の可能性がない)場合も使用できますがlock、これらのシナリオでも、System.Threading.ReaderWriterLockSlim代わりに使用したいと思います。
ところで-いい読み物!