2010-09-16 33 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) 
相关问题