他の人は「なぜ?」に対処しました。ただし、プリミティブAdd(ref double, double)
を使用して独自の をロールするのは簡単です。CompareExchange
public static double Add(ref double location1, double value)
{
double newCurrentValue = location1; // non-volatile read, so may be stale
while (true)
{
double currentValue = newCurrentValue;
double newValue = currentValue + value;
newCurrentValue = Interlocked.CompareExchange(ref location1, newValue, currentValue);
if (newCurrentValue == currentValue)
return newValue;
}
}
CompareExchange
現在の値が に等しい場合、 の値をlocation1
に設定します。これはアトミックでスレッドセーフな方法で行われるため、ロックに頼ることなく単独で信頼できます。newValue
currentValue
なぜwhile (true)
ループ?このようなループは、楽観的並行アルゴリズムを実装する場合の標準です。現在の値が と異なる場合、CompareExchange
は変化しません。私は初期化しました- 不揮発性読み取りを行います (これは古い可能性がありますが、値をチェックするため、正確性は変わりません)。現在の値 (まだ) が から読み取った値である場合、は値を に変更します。そうでない場合は、によって返される新しい現在の値で再試行する必要があります。location1
currentValue
currentValue
location1
CompareExchange
location
CompareExchange
newValue
CompareExchange
CompareExchange
次の時間までに別のスレッドによって値が変更されると、CompareExchange
再び失敗し、別の再試行が必要になります。これは理論的には永遠に続く可能性があるため、ループが発生します。複数のスレッドから常に値を変更している場合を除き、CompareExchange
は、現在の値がまだ不揮発性読み取りによってlocation1
得られたものである場合は 1 回だけ呼び出され、異なる場合は 2 回呼び出されます。