他の人は「なぜ?」に対処しました。ただし、プリミティブ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に設定します。これはアトミックでスレッドセーフな方法で行われるため、ロックに頼ることなく単独で信頼できます。newValuecurrentValue
なぜwhile (true)ループ?このようなループは、楽観的並行アルゴリズムを実装する場合の標準です。現在の値が と異なる場合、CompareExchangeは変化しません。私は初期化しました- 不揮発性読み取りを行います (これは古い可能性がありますが、値をチェックするため、正確性は変わりません)。現在の値 (まだ) が から読み取った値である場合、は値を に変更します。そうでない場合は、によって返される新しい現在の値で再試行する必要があります。location1currentValuecurrentValuelocation1CompareExchangelocationCompareExchangenewValueCompareExchangeCompareExchange
次の時間までに別のスレッドによって値が変更されると、CompareExchange再び失敗し、別の再試行が必要になります。これは理論的には永遠に続く可能性があるため、ループが発生します。複数のスレッドから常に値を変更している場合を除き、CompareExchangeは、現在の値がまだ不揮発性読み取りによってlocation1得られたものである場合は 1 回だけ呼び出され、異なる場合は 2 回呼び出されます。