【发布时间】:2014-09-08 14:31:32
【问题描述】:
(这是重复的:How to correctly read an Interlocked.Increment'ed int field? 但是,在阅读了答案和 cmets 之后,我仍然不确定正确的答案。)
有些代码我不拥有并且无法更改为使用在几个不同线程中递增 int 计数器 (numberOfUpdates) 的锁。所有调用使用:
Interlocked.Increment(ref numberOfUpdates);
我想在我的代码中读取 numberOfUpdates。现在,由于这是一个 int,我知道它不能撕裂。但是,确保我获得最新价值的最佳方式是什么?看来我的选择是:
int localNumberOfUpdates = Interlocked.CompareExchange(ref numberOfUpdates, 0, 0);
或者
int localNumberOfUpdates = Thread.VolatileRead(numberOfUpdates);
两者都可以工作吗(无论优化、重新排序、缓存等如何,都可以提供最新的价值)?一个比另一个更受欢迎吗?还有第三种更好的选择吗?
【问题讨论】:
-
这似乎是一个常见问题,请参阅stackoverflow.com/questions/516863/…。但我仍然不清楚 Thread.VolatileRead 或 Interlocked.CompareExchange 是否更好或无关紧要。
-
一个值得考虑的问题:接下来会发生什么依赖于获取 numberOfUpdates 的“最新”值,以及它如何与任何增加它的东西相互作用?如果您读取稍微陈旧的缓存值会有什么后果?
-
没什么。如果我得到一个旧的值,那会很好,只要我最终看到正确的值。我不太担心读取 int 并获得 100 毫秒前的值。我更关心一些被优化或缓存在寄存器等中的东西,以便我的读取 never 看到更新的值。我不明白这怎么会发生。但我只是认为我应该以最好的、最惯用的 C# 方式阅读 int。而且我不确定 Interlocked.CompareExchange 或 Thread.VolatileRead 是否更好,或者是否没有区别。
-
最好的方法是一开始就不要这样做。多线程是个坏主意。如果你必须有多个线程,共享内存是个坏主意。如果你必须共享内存,锁规避是一个坏主意。 对共享内存的每次访问都加锁。如果结果证明这是一个不可接受的性能负担,并且您无法消除争用,或者即使没有争用也存在负担,那么只有那么您才应该考虑评估低锁定解决方案。
-
我不需要性能,所以没有低锁代码的目标。其他开发人员已经在使用任何锁之外的 Interlocked.* 来修改这个整数,所以锁不是我的选择。我只需要以最好的方式阅读这个 int ,因为它是在锁之外更新的(尽管据我所知总是使用 Interlocked.* )。如果我从头开始,我会锁定所有地方以使其更简单。
标签: c# .net multithreading interlocked interlocked-increment