13

System.Threading.Interlocked.CompareExchangeoperator は、Compare-And-Swap 操作のアトミック (スレッドセーフ) C# 実装を提供します。

たとえば、int i = 5; Interlocked.CompareExchange(ref i, 10, 5);このコマンドの後、int i は値 = 10 になります。また、比較と交換はアトミックに行われます (単一操作)。

これをクラスインスタンスで使用しようとすると、比較が失敗し、値が交換されません。

   public class X
   {
       public int y;
       public X(int val) { y = val; }
   }

今私がするとき

    X a = new X(1);
    X b = new X(1);
    X c = new X(2);
    Interlocked.CompareExchange<X>(ref a, c, b);

比較および交換操作は失敗します。そこで、クラス X の Equals と == 演算子を次のようにオーバーライドしました。

    public override bool Equals(object obj) { return y == ((X) obj).y; }

だから、今は として取得Interlocked.Equals(a,b)しますtrueが、CompareExchange操作はまだ失敗します。

これを行う方法はありますか?2 つのクラス インスタンスを比較し、それらの 1 つに比較に基づいて値を割り当てたいと考えています。

4

3 に答える 3

23

いいえ、できません。

Interlocked.CompareExchange基本的に、メモリアドレスの内容をアトミックに比較および交換できるアセンブリ命令に直接マップされます。32ビットモードでは、64ビットバージョンの命令(および32ビットバージョンと16ビットバージョン)が利用可能であり、64ビットモードでは128ビットバージョンが利用可能であると思います。しかし、それだけです。CPUには、「特定の機能に基づいて.NETクラスをスワップEqualsする」命令はありません。

任意の等式関数を使用して任意のオブジェクトを交換する場合は、ロックまたはその他の同期メカニズムを使用して、自分で行う必要があります。

オブジェクト参照で機能する関数のオーバーロードがありますが、上記の理由で参照の同等性を使用します。単に参照を比較してから、それらを交換します。Interlocked.CompareExchange

あなたのコメントに応えて、構造体を使用しても問題は解決しません。この場合も、CPUは特定の固定サイズの値をアトミックに比較およびスワップすることしかできず、抽象データ型の概念はありません。参照自体は有効なサイズであり、CPUによって別の参照と比較できるため、参照型を使用できます。ただし、CPUは、参照が指すオブジェクトについては何も知りません。

于 2011-07-14T08:31:49.037 に答える
5

の通常の使用はInterlocked.CompareExchange次のパターンです。

SomeType oldValue;
do
{
  oldValue = someField;
  someType newValue = [Computation based on oldValue]
} while (CompareExchange(ref someField, newValue, oldValue) != oldValue);

oldValue基本的な考え方は、フィールドが読み込まれてCompareExchangeから処理されるまでの間にフィールドが変更されない場合、フィールドnewValueに格納する必要のある値を保持するということです。計算中に他の何かがそれを変更した場合、計算の結果は破棄され、新しい値を使用して計算が繰り返されます。計算が高速である場合、正味の効果は本質的に、任意の計算がアトミックであるかのように動作できるようにすることです。

等式を使用してCompare-Exchangeスタイルの操作をEquals()実行する場合は、おそらく次のような操作を行う必要があります。

SomeType newValue = desired new value;
SomeType compareValue = desired comparand;
SomeType oldValue;
do
{
  oldValue = someField;
  if (!oldValue.Equals(compareValue) return oldValue;
} while (CompareExchange(ref someField, newValue, oldValue) != oldValue);
return oldValue;

someFieldに等しいと比較されるオブジェクトへの参照を保持しcompareValue、比較中に別のオブジェクトへの参照を保持するように変更された場合、その新しい値は。に対してチェックされることに注意してくださいcompareValue。このプロセスは、フィールドフィールドから読み取られた値が比較対象と等しくないことが比較で報告されるまで、またはフィールドの値がEquals()CompareExchangeメソッドの両方が完了するのに十分な時間変更されないままになるまで繰り返されます。

于 2013-02-11T23:54:40.780 に答える