その他ました「なぜ?」と対処した。しかしCompareExchange
プリミティブを使用して、独自のAdd(ref double, double)
をロールバックすることは簡単です:
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
は、現在の値がcurrentValue
に等しい場合、newValue
するlocation1
の値を設定します。スレッドセーフなアトミックな方法で実行するので、ロックに頼らずに、それだけで頼りにすることができます。
なぜwhile (true)
ループですか?このようなループは、楽観的並列アルゴリズムを実装する際の標準です。現在の値がcurrentValue
と異なる場合、CompareExchange
はlocation1
に変更されません。私はcurrentValue
〜location1
を初期化しました - 不揮発性の読み取りを行っています(古くなっているかもしれませんが、値はCompareExchange
でチェックされます)。現在の値(まだ)がlocation
から読み取られた場合、CompareExchange
はnewValue
に値を変更します。そうでない場合は、CompareExchange
によって返される新しい現在の値でCompareExchange
を再試行する必要があります。
もう一度値を変更すると次のCompareExchange
の時刻まで別のスレッドで値が変更されますが、もう一度やり直す必要があります。これは理論上永遠に続くことができます。値が複数のスレッドから常に変更されていない限り、CompareExchange
は、現在の値がまだ不揮発性の読み取り値であるlocation1
が得られた場合、または異なる場合は2度だけ呼び出される可能性が最も高いです。
リンクはもうアクティブではありません。ここにインターネットアーカイブからのバックアップがありますhttps://web.archive.org/web/20160319061137/http://www.codemaestro.com/reviews/8 –