我一直在寻找使用Interlocked
的线程安全计数器实现,该实现支持按任意值递增,并直接从 Interlocked.CompareExchange
文档中找到了此示例(为简单起见,略有更改):
private int totalValue = 0;
public int AddToTotal(int addend)
{
int initialValue, computedValue;
do
{
// How can we get away with not using a volatile read of totalValue here?
// Shouldn't we use CompareExchange(ref TotalValue, 0, 0)
// or Thread.VolatileRead
// or declare totalValue to be volatile?
initialValue = totalValue;
computedValue = initialValue + addend;
} while (initialValue != Interlocked.CompareExchange(
ref totalValue, computedValue, initialValue));
return computedValue;
}
public int Total
{
// This looks *really* dodgy too, but isn't
// the target of my question.
get { return totalValue; }
}
我知道这段代码正在尝试做的事情,但是我不确定在分配给要添加到的临时变量时不使用 volatile 的共享变量读取方法如何解决。
initialValue
是否有可能在整个循环中保持陈旧的值,从而使该函数永不返回?还是CompareExchange
中的内存屏障(?)消除了这种可能性?任何见识将不胜感激。编辑:我应该澄清一下,我理解如果
CompareExchange
导致上次totalValue
调用之后对CompareExchange
的后续读取是最新的,那么此代码就可以了。但是可以保证吗? 最佳答案
托管的Interlocked.CompareExchange
直接映射到Win32 API中的 InterlockedCompareExchange
(还有64 bit version)。
如您在函数签名中所看到的, native API要求目标必须是 volatile 的,即使托管API并不需要该目标,但乔·达菲(Joe Duffy)在其出色的著作Concurrent Programming on Windows中建议使用volatile。