Mic*_*lli 35 .net c# multithreading interlocked interlocked-increment
(这是重复:如何正确读取Interlocked.Increment'ed int字段?但是,在阅读了答案和评论之后,我仍然不确定正确的答案.)
有些代码我不拥有,也无法更改为使用在几个不同线程中增加int计数器(numberOfUpdates)的锁.所有通话都使用:
Interlocked.Increment(ref numberOfUpdates);
Run Code Online (Sandbox Code Playgroud)
我想在我的代码中读取numberOfUpdates.既然这是一个int,我知道它不会撕裂.但是,确保我获得最新价值的最佳方法是什么?看起来我的选择是:
int localNumberOfUpdates = Interlocked.CompareExchange(ref numberOfUpdates, 0, 0);
Run Code Online (Sandbox Code Playgroud)
要么
int localNumberOfUpdates = Thread.VolatileRead(numberOfUpdates);
Run Code Online (Sandbox Code Playgroud)
两者都有效(无论优化,重新排序,缓存等,都可以提供最新的价值)?一个比另一个更受欢迎吗?还有第三种选择更好吗?
Pat*_*sel 34
我坚信,如果您使用互锁来增加共享数据,那么您应该在访问共享数据的任何地方使用互锁.同样,如果您在此处使用插入您喜欢的同步原语来增加共享数据,那么您应该在访问该共享数据的任何位置使用插入您喜欢的同步原语.
int localNumberOfUpdates = Interlocked.CompareExchange(ref numberOfUpdates, 0, 0);
Run Code Online (Sandbox Code Playgroud)
会给你你正在寻找的东西.正如其他人所说,互锁操作是原子的.因此Interlocked.CompareExchange将始终返回最新值.我一直用它来访问像计数器这样的简单共享数据.
我对Thread.VolatileRead并不熟悉,但我怀疑它也会返回最近的值.如果只是为了保持一致,我会坚持使用互锁方法.
附加信息:
我建议你看一下Jon Skeet的回答,为什么你可能想要回避Thread.VolatileRead():Thread.VolatileRead Implementation
Eric Lippert在他的博客http://blogs.msdn.com/b/ericlippert/archive/2011/06/16/atomicity-volatility-and-immutability-are-different上讨论了C#内存模型的波动性和保证.-part-three.aspx.直接从马口:"我不会尝试编写任何低锁代码,除了互锁操作最琐碎的用法.我将"挥发性"的用法留给真正的专家."
我同意Hans的意见,即该值至少会持续几秒,但是如果你有一个不可接受的用例,它可能不适合像C#这样的垃圾收集语言或者非实时的时间OS.Joe Duffy在这里有一篇关于互锁方法及时性的文章:http://joeduffyblog.com/2008/06/13/volatile-reads-and-writes-and-timeliness/
Thread.VolatileRead(numberOfUpdates)是你想要的.numberOfUpdates是一个Int32,因此默认情况下你已经具有原子性,Thread.VolatileRead并将确保处理波动性.
如果numberOfUpdates定义为volatile int numberOfUpdates;您不必执行此操作,因为它的所有读取都将是易失性读取.
关于是否Interlocked.CompareExchange更合适似乎存在混淆.请考虑以下两个文档摘录.
从Thread.VolatileRead文档:
读取字段的值.该值是计算机中任何处理器写入的最新值,无论处理器数量或处理器缓存状态如何.
从Interlocked.CompareExchange文档:
比较两个32位有符号整数是否相等,如果它们相等,则替换其中一个值.
就这些方法的陈述行为而言,Thread.VolatileRead显然更为合适.您不想与numberOfUpdates其他值进行比较,也不想替换其值.你想要读它的价值.
Lasse在他的评论中提出了一个很好的观点:你可能最好使用简单的锁定.当其他代码想要更新时,numberOfUpdates它会执行以下操作.
lock (state)
{
state.numberOfUpdates++;
}
Run Code Online (Sandbox Code Playgroud)
当您想要阅读它时,您会执行以下操作.
int value;
lock (state)
{
value = state.numberOfUpdates;
}
Run Code Online (Sandbox Code Playgroud)
这将确保您对原子性和波动性的要求,而无需深入研究更加模糊,相对较低级别的多线程原语.
两者都有效吗(无论优化、重新排序、缓存等如何,都可能提供最新的价值)?
不,你获得的值总是陈旧的。该值可能有多陈旧是完全无法预测的。绝大多数情况下,它会过时几纳秒,具体取决于您对值采取行动的速度。但没有合理的上限:
无论您对价值做什么,都需要考虑到这一点。不用说,这可能非常非常困难。实际例子很难找到。.NET Framework 是一大块饱经战火的代码。您可以从参考源中看到对 VolatileRead 用法的交叉引用。点击次数:0。
| 归档时间: |
|
| 查看次数: |
11929 次 |
| 最近记录: |