Interlocked.Increment
および関連するメソッドは、ハードウェア命令に依存して単一の 32 ビットまたは 64 ビット メモリ値の同期変更を実行し、同じ値にアクセスする複数のスレッドが古いデータを読み書きしないようにします。これが必要なのは、ハードウェア レベルでは、プロセッサがメモリ値のローカル/バス コピーを持っているためです (パフォーマンスのために、バス メモリまたは CPU キャッシュと呼ばれることが多い)。
lock(){}
単一の整数値ではなく、コードのセクションの同期を実行します。また、ハードウェア命令に依存して変数へのアクセスを同期する代わりに、結果のコードはオペレーティング システムの同期プリミティブ (ハードウェアではなくソフトウェア) に依存して、メモリとコード実行を保護します。
さらに、lock() を使用するとメモリ バリアが発行され、複数の CPU から同じ変数にアクセスしても、同期された (古くない) データが生成されることが保証されます。これは、メモリバリアとフェンシングを明示的に実行する必要がある他の言語/プラットフォームには当てはまりません。
Interlocked
ハードウェアは必要な同期を実行するためのネイティブ サポートを備えているため、整数値に対してメソッドを使用する方が効率的です。ただし、このハードウェア サポートは __int32 や __int64 などのネイティブの積分に対してのみ存在します。ハードウェアには高レベルの複合型の概念がないため、そのような高レベルのメソッドがInterlocked
型から公開されることはありません。したがって、または派生型Interlocked
の割り当てを同期するために使用することはできません。System.String
System.Object
(下位レベルの言語を使用している場合、文字列値へのポインターの割り当ては同じハードウェア命令で実行できますが、.NET では文字列オブジェクトはポインターとして表されないため、実際にはそうではありません。どの「純粋な」.NET 言語でも可能です.安全でないメソッドを使用してポインターを解決し、必要に応じて文字列値のインターロック割り当てを行うことができるという事実を避けていますが、これが本当にそうであるとは思いませんあなたが求めていること、さらにこれは Interlocked ではサポートされていません。これは、ボンネットの下で GC ピンニングが発生する必要があり、使用するよりも高価で侵襲的になる可能性が高いためlock()
です。)
したがって、同期された「参照型」の変更/割り当てには、同期プリミティブ (つまり、lock(){}、Monitor など) を使用する必要があります。同期する必要があるのが単一の整数値 (Int32、Int64) だけである場合は、Interlocked メソッドを使用する方が効率的です。同期する整数値が複数ある場合 (たとえば、1 つの整数をインクリメントしながら 2 番目の整数をデクリメントし、両方を 1 つの論理演算として同期する必要がある場合) には、lock() ステートメントを使用するのが理にかなっている場合があります。