(这是重复:How to correctly read an Interlocked.Increment'ed int field? 但是,在阅读了答案和评论后,我仍然不确定正确答案。)
有一些代码我不拥有并且无法更改为使用在几个不同线程中递增 int 计数器 (numberOfUpdates) 的锁。所有调用都使用:
Interlocked.Increment(ref numberOfUpdates);
我想在我的代码中读取 numberOfUpdates。现在因为这是一个整数,我知道它不能撕裂。但确保我获得最新值(value)的最佳方法是什么?看来我的选择是:
int localNumberOfUpdates = Interlocked.CompareExchange(ref numberOfUpdates, 0, 0);
要么
int localNumberOfUpdates = Thread.VolatileRead(numberOfUpdates);
无论优化、重新排序、缓存等如何,两者都可以工作吗(在尽可能提供最新值(value)的意义上)?一个比另一个更受欢迎吗?有没有更好的第三种选择?
最佳答案
我坚信,如果您使用互锁来增加共享数据,那么您应该在访问共享数据的任何地方使用互锁。同样,如果您在此处使用插入您最喜欢的同步原语来增加共享数据,那么您应该在此处在您访问该共享数据的任何地方使用插入您最喜欢的同步原语。
int localNumberOfUpdates = Interlocked.CompareExchange(ref numberOfUpdates, 0, 0);
会给你你正在寻找的东西。正如其他人所说,互锁操作是原子的。因此 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-part-three.aspx 中讨论了 C# 内存模型的波动性和保证。直接从马嘴里说:“除了 Interlocked 操作的最琐碎的用法之外,我不会尝试编写任何低锁代码。我将“ volatile ”的用法留给真正的专家。”
而且我同意 Hans 的观点,即该值至少会过时几个 ns,但是如果您有一个 Not Acceptable 用例,它可能不太适合像 C# 这样的垃圾收集语言或非真实的 -时间操作系统。 Joe Duffy 有一篇关于互锁方法的及时性的好文章:http://joeduffyblog.com/2008/06/13/volatile-reads-and-writes-and-timeliness/
关于c# - 读取由 Interlocked 在其他线程上更新的 int,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24808291/