【发布时间】:2011-09-26 14:33:08
【问题描述】:
我一直在寻找一个使用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; }
}
我知道这段代码试图做什么,但我不确定在分配给添加到的临时变量时如何不使用共享变量的易失性读取。
initialValue 是否有可能在整个循环中保持一个陈旧的值,使函数永远不会返回?还是CompareExchange 中的内存屏障(?)消除了这种可能性?任何见解将不胜感激。
编辑:我应该澄清一下,我理解如果CompareExchange 导致totalValue 的后续读取在最后 CompareExchange 调用,那么这段代码就可以了。但这能保证吗?
【问题讨论】:
-
是的,这可能会在内存模型较弱的处理器上烧毁内核一段时间。没有说这是高效代码,只是说它是正确代码。保证退出循环,最终线程调度器有内存屏障。
-
@HansPassant 经过这么长时间,我得出的结论是代码在技术上并不正确。担心的是,由于引入了读取,CompareExchange 的最后一个参数可能包含不一致的值。我已经编辑了我的答案来解释。
标签: c# .net multithreading volatile interlocked