我正在阅读Joe Duffy关于Volatile reads and writes, and timeliness的帖子,并试图理解帖子中最后一个代码示例的某些内容:
while (Interlocked.CompareExchange(ref m_state, 1, 0) != 0) ;
m_state = 0;
while (Interlocked.CompareExchange(ref m_state, 1, 0) != 0) ;
m_state = 0;
…
第二个CMPXCHG操作执行时,是否使用内存屏障以确保m_state的值是最新写入它的值?或者它只会使用已经存储在处理器缓存中的某个值?(假设m_state没有声明为volatile)。
如果我理解正确,如果CMPXCHG不使用内存屏障,则整个锁获取过程将不公平,因为很可能第一个获取锁的线程将是获取后续所有锁的线程。我理解正确吗,还是我漏掉了什么?
编辑:实际上,主要问题是在调用CompareExchange之前是否会导致内存屏障读取m_state的值。 所以当它们再次尝试调用CompareExchange时,分配0是否可见于所有线程。
Interlocked.CompareExchange
在 ARM / AArch64 上也是如此吗?还是这只是针对 x86 的 C# 实现细节,不属于语言标准保证的一部分? - Peter Cordesdmb ish
。微软的C++_InterlockedIncrement
intrinsic文档表明有_acq
和_rel
版本,推测普通版本为seq_cst。(因为没有_relaxed或_sc)。 - Peter Cordesldaxr
/stlxr
)操作可能与完整的屏障不完全相同,但我认为它仍将阻止两侧操作彼此重新排序,即使自己的load / store 可能会出现分裂。这比仅使用ldxr
/stxr
(具有独占但没有获取和释放属性,例如C ++memory_order_relaxed
)的完全“松散”CAS要接近得多。 - Peter Cordes(数据内存屏障:内部共享)用于C++
_InterlockedIncrement`。因此,至少该实现使其成为一个真正的全障碍,超越了序列一致操作,我猜测C#也可能如此。只剩下任何书面规范是否要求这样的问题。 - Peter Cordes