假设我有一个非易失性的int字段,以及一个它Interlocked.Increment的线程.另一个线程可以直接安全地读取它,还是读取也需要互锁?
我以前认为我必须使用互锁读取来保证我看到当前值,因为毕竟,该字段不是易失性的.我一直在Interlocked.CompareExchange(int, 0, 0)努力实现这一目标.
但是,我偶然发现了这个答案,这表明实际的普通读取总会看到Interlocked.Incremented值的当前版本,并且因为int读取已经是原子的,所以不需要做任何特殊的事情.我还发现了Microsoft拒绝Interlocked.Read(ref int)请求的请求,进一步表明这完全是多余的.
那么我能真正安全地阅读这样一个int领域的最新价值Interlocked吗?
以下代码
using System.Threading;
class Test
{
volatile int counter = 0;
public void Increment()
{
Interlocked.Increment(ref counter);
}
}
Run Code Online (Sandbox Code Playgroud)
引发以下编译器警告:
"A reference to a volatile field will not be treated as volatile"
Run Code Online (Sandbox Code Playgroud)
我在这里做错了什么来提出这个警告?为什么编译器会对此发出警告?
(这是重复:如何正确读取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)
两者都有效(无论优化,重新排序,缓存等,都可以提供最新的价值)?一个比另一个更受欢迎吗?还有第三种选择更好吗?
我正在阅读Joe Duffy关于Volatile读取和写入以及及时性的帖子,我正在尝试理解帖子中最后一个代码示例:
while (Interlocked.CompareExchange(ref m_state, 1, 0) != 0) ;
m_state = 0;
while (Interlocked.CompareExchange(ref m_state, 1, 0) != 0) ;
m_state = 0;
…
Run Code Online (Sandbox Code Playgroud)
当执行第二CMPXCHG操作,它使用一个内存屏障,以保证价值m_state确实写入的最新值?或者它只是使用已存储在处理器缓存中的某些值?(假设m_state未声明为volatile).
如果我理解正确,如果CMPXCHG不会使用内存屏障,那么整个锁获取过程将不公平,因为第一个获取锁的线程很可能是将获得所有锁的线程.以下锁.我是否理解正确,或者我错过了什么?
编辑:主要问题实际上,在尝试读取m_state的值之前,调用CompareExchange是否会导致内存屏障.因此,当尝试再次调用CompareExchange时,是否所有线程都可以看到赋值0.