2010-09-16 54 views
3

我有多個線程訪問變量。我知道如何編寫自旋鎖,並使用Threading.Interlocked方法來增加等變量。如何在不使用鎖的情況下在.Net中設置最小值?

不過,我想執行的等效:

a = Math.Min(a, b) 
or 
a = a | 10 

...但不使用一個關鍵部分。這可能嗎?我知道第二行可能在彙編程序中,但沒有Interlocked.Or方法。

回答

2

這裏是模擬互鎖操作的一般模式。

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 | valuecomputed = initial < value ? initial : value。其他一切都保持不變。

+0

我認爲你的Thread.MemoryBarrier建議是正確的解決方案。建議的模式仍然可能導致爭論中的計算錯誤。 – IamIC 2010-09-22 06:17:08

+0

@IanC:我沒有看到如何。如果另一個線程使用這個模式將'a'設置爲更小的值,那麼當前線程將不得不繞着循環再次旋轉?我認爲真正的問題是,即使在函數啓動之前,傳遞給'value'參數的'b'值可能已經改變,但從函數的角度來看,計算值和重新分配應該是正確的。 – 2010-09-22 12:14:23

+0

現在我明白你的意思了!你100%正確。感謝Brian! – IamIC 2010-09-22 14:37:07

2

如果你沒有預料到很多的爭論,那麼可能是這樣的? (如果可能有很多爭用,那麼普通鎖可能會更有效。)

int original; // assuming here that a is an int 
do 
{ 
    original = a; 
} while (Interlocked.CompareExchange(ref a, original | 10, original) != original)