InterlockedExchange和内存可见性

我已阅读文章同步和多处理器问题 ,我有一个关于InterlockedCompareExchange和InterlockedExchange的问题。 问题实际上是关于文章中的最后一个例子。 它们有两个variablesiValuefValueHasBeenComputed并且在CacheComputedValue()中它们使用InterlockedExchange修改它们中的每一个:

 InterlockedExchange ((LONG*)&iValue, (LONG)ComputeValue()); // don't understand InterlockedExchange ((LONG*)&fValueHasBeenComputed, TRUE); // understand 

我明白,我可以使用InterlockedExchange来修改iValue但是这样做足够了

 iValue = ComputeValue(); 

那么实际上是否需要使用InterlockedExchange来设置iValue? 或者其他线程会正确地看到iValue,即使iValue = ComputeValue(); 。 我的意思是其他线程将正确地看到iValue,因为它之后有InterlockedExchange

还有一篇论文是针对微软Native Code平台的基于原理的顺序存储模型 。 3.1.1的例子或多或less有相同的代码。 其中一个推荐Make y interlocked 。 注意 – 不是yx

更新
只是为了澄清这个问题。 问题是我看到一个矛盾。 “同步和多处理器问题”的示例使用两个InterlockedExchange 。 相反,在3.1.1“Basic Reodering”(我认为与第一个例子非常相似)的例子中,Herb Sutter给出了这个推荐

“让y互锁:如果y互锁,那么y就没有竞赛,因为它是可以自动更新的,并且在x上没有比赛,因为a – > b – > d。

。 在这个草案草案不要使用两个互锁variables(如果我是正确的,他的意思是使用InterlockedExchange只为y )。

他们这样做是为了防止部分读取/写入,如果iValue的地址不与保证原子访问的地址对齐。 当两个或两个以上的物理线程试图同时写入这个值,或者一个读取和一个同时写入时,就会出现这个问题。

作为第二点,应该指出的是,商店并不总是全局可见的,它们只有在通过栅栏或总线锁定进行序列化时才可见。

您只需使用InterlockedExchange获得一个原子操作即可。 为什么你需要它? 导致InterlockedExchange做2件事。

  1. 取代变量的值
  2. 返回一个旧值

如果你在2个操作中做同样的事情(因此首先检查值然后替换),如果在这两个操作之间发生其他指令(在另一个线程上),则可能会被拧紧。

而且你也防止这个值的数据竞争。 在这里你可以得到一个很好的解释,为什么在LONG上读/写不是原子的

对于你所观察到的矛盾,有两个合理的解决方案。

一个是,第二个文件在这方面完全是错误的。 毕竟是草稿。 我注意到你所提到的例子明确指出,程序员不能依赖写入是原子的,这意味着两个写入必须确实是互锁的。

另一个是在这个特定的例子中可能并不需要额外的互锁,因为这是一个非常特殊的情况:变量只有一个位被改变。 然而,正在开发的规范似乎没有提到这是一个前提,所以我怀疑这是故意的。

我认为这个讨论有一个问题的答案: 隐性内存障碍 。

问题 :在T1和T2上调用InterlockedExchange(隐式全屏)后,T2会“看到”T1之前的写入操作吗? (A,B和C变量),即使这些变量不在Foo和Bar的同一缓存行上吗?

答案是 – 由InterlockedExchange生成的完整栅栏将保证对A,B和C的写入不会在InterlockedExchange调用中隐含的栅栏之后重新排序。 这是内存屏障语义的一点。 他们不需要在同一个缓存行上。

内存障碍:软件黑客的硬件视图和无锁编程Xbox 360和Microsoft Windows的注意事项也是令人</s>目的。