我有多个线程访问变量。我知道如何编写自旋锁,并使用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