我有多個線程訪問變量。我知道如何編寫自旋鎖,並使用Threading.Interlocked方法來增加等變量。如何在不使用鎖的情況下在.Net中設置最小值?
不過,我想執行的等效:
a = Math.Min(a, b)
or
a = a | 10
...但不使用一個關鍵部分。這可能嗎?我知道第二行可能在彙編程序中,但沒有Interlocked.Or方法。
我有多個線程訪問變量。我知道如何編寫自旋鎖,並使用Threading.Interlocked方法來增加等變量。如何在不使用鎖的情況下在.Net中設置最小值?
不過,我想執行的等效:
a = Math.Min(a, b)
or
a = a | 10
...但不使用一個關鍵部分。這可能嗎?我知道第二行可能在彙編程序中,但沒有Interlocked.Or方法。
這裏是模擬互鎖操作的一般模式。
public static T InterlockedOperation<T>(ref T location, T value)
{
T initial, computed;
do
{
initial = location;
computed = op(initial, value); // initial | value
}
while (Interlocked.CompareExchange(ref location, computed, initial) != initial);
return computed;
}
min操作是一個完全不同的故事。這裏的問題是有兩個存儲位置在使用。此外,我們只對閱讀它們感興趣。這意味着我們只需要擔心內存障礙問題。用volatile
裝飾你的領域,或者在計算最小值之前,明確地調用Thread.MemoryBarrier
。
編輯:我錯過了最小操作的結果分配給a
的事實。你實際上可以使用我在上面定義的模式,但是不要做computed = initial | value
做computed = initial < value ? initial : value
。其他一切都保持不變。
如果你沒有預料到很多的爭論,那麼可能是這樣的? (如果可能有很多爭用,那麼普通鎖可能會更有效。)
int original; // assuming here that a is an int
do
{
original = a;
} while (Interlocked.CompareExchange(ref a, original | 10, original) != original)
我認爲你的Thread.MemoryBarrier建議是正確的解決方案。建議的模式仍然可能導致爭論中的計算錯誤。 – IamIC 2010-09-22 06:17:08
@IanC:我沒有看到如何。如果另一個線程使用這個模式將'a'設置爲更小的值,那麼當前線程將不得不繞着循環再次旋轉?我認爲真正的問題是,即使在函數啓動之前,傳遞給'value'參數的'b'值可能已經改變,但從函數的角度來看,計算值和重新分配應該是正確的。 – 2010-09-22 12:14:23
現在我明白你的意思了!你100%正確。感謝Brian! – IamIC 2010-09-22 14:37:07