3

Interlocked.Incrementと の機能を理解していますlock()。しかし、どちらをいつ使用するかについて混乱しています。コードの領域をロックすることを意図しているのに対し、私が知る限り、Interlocked.Increment共有されたint / long値をインクリメントします。lock()

たとえば、文字列値を更新したい場合は次のようにできますlock():

lock(_object)
{
    sharedString = "Hi";
}

Interlockedただし、これはクラスでは不可能です。

  • を介してこれを行うことができないのはなぜInterlockedですか?
  • これらの同期メカニズムの違いは何ですか?
4

3 に答える 3

7

Interlocked.Incrementおよび関連するメソッドは、ハードウェア命令に依存して単一の 32 ビットまたは 64 ビット メモリ値の同期変更を実行し、同じ値にアクセスする複数のスレッドが古いデータを読み書きしないようにします。これが必要なのは、ハードウェア レベルでは、プロセッサがメモリ値のローカル/バス コピーを持っているためです (パフォーマンスのために、バス メモリまたは CPU キャッシュと呼ばれることが多い)。

lock(){}単一の整数値ではなく、コードのセクションの同期を実行します。また、ハードウェア命令に依存して変数へのアクセスを同期する代わりに、結果のコードはオペレーティング システムの同期プリミティブ (ハードウェアではなくソフトウェア) に依存して、メモリとコード実行を保護します。

さらに、lock() を使用するとメモリ バリアが発行され、複数の CPU から同じ変数にアクセスしても、同期された (古くない) データが生成されることが保証されます。これは、メモリバリアとフェンシングを明示的に実行する必要がある他の言語/プラットフォームには当てはまりません。

Interlockedハードウェアは必要な同期を実行するためのネイティブ サポートを備えているため、整数値に対してメソッドを使用する方が効率的です。ただし、このハードウェア サポートは __int32 や __int64 などのネイティブの積分に対してのみ存在します。ハードウェアには高レベルの複合型の概念がないため、そのような高レベルのメソッドがInterlocked型から公開されることはありません。したがって、または派生型Interlockedの割り当てを同期するために使用することはできません。System.StringSystem.Object

(下位レベルの言語を使用している場合、文字列値へのポインターの割り当ては同じハードウェア命令で実行できますが、.NET では文字列オブジェクトはポインターとして表されないため、実際にはそうではありません。どの「純粋な」.NET 言語でも可能です.安全でないメソッドを使用してポインターを解決し、必要に応じて文字列値のインターロック割り当てを行うことができるという事実を避けていますが、これが本当にそうであるとは思いませんあなたが求めていること、さらにこれは Interlocked ではサポートされていません。これは、ボンネットの下で GC ピンニングが発生する必要があり、使用するよりも高価で侵襲的になる可能性が高いためlock()です。)

したがって、同期された「参照型」の変更/割り当てには、同期プリミティブ (つまり、lock(){}、Monitor など) を使用する必要があります。同期する必要があるのが単一の整数値 (Int32、Int64) だけである場合は、Interlocked メソッドを使用する方が効率的です。同期する整数値が複数ある場合 (たとえば、1 つの整数をインクリメントしながら 2 番目の整数をデクリメントし、両方を 1 つの論理演算として同期する必要がある場合) には、lock() ステートメントを使用するのが理にかなっている場合があります。

于 2013-12-14T22:10:39.113 に答える
6

Interlocked.Incrementint共有変数をインクリメントするために使用でき、使用する必要があります。機能的に使用することInterlocked.Incrementは次と同じです:

lock(_object)
{
   counter++;
}

ただし、Interlocked.Incrementパフォーマンスの面でははるかに安価です。

于 2012-09-07T09:13:32.163 に答える
0

参照値を交換し、アトミック操作で元の値を返したい場合は、 を使用できますInterlocked.ExchangeInterlocked.Incrementそれが言うことを正確に行います:それは数値をインクリメントします。

ただし、変数への参照値の代入、または任意の 32 ビット値型は、とにかく .NET ではアトミックです。後者が成り立たない、私が考えることができる唯一の他のケースは、パックされた構造を作成し、コンパイラがメンバーを4バイト境界で整列させないように強制する属性を設定する場合です(ただし、これはあなたが行うことではありません本当によくある)。

于 2012-09-07T09:16:19.290 に答える