8

我已阅读文章同步和多处理器问题,并且对 InterlockedCompareExchange 和 InterlockedExchange 有疑问。这个问题实际上是关于文章中的最后一个例子。它们有两个变量iValuefValueHasBeenComputed并且在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后面有。

还有论文A Principle-Based Sequential Memory Model for Microsoft Native Code Platforms。有一个 3.1.1 示例,其代码或多或少相同。推荐之一Make y interlocked。注意 - 不是两者yx

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

“使 y 互锁:如果 y 互锁,则 y 上没有竞争,因为它是原子可更新的,并且 x 上没有竞争,因为 a -> b -> d。”

. 在这个草稿草稿中,不要使用两个互锁的变量(如果我是对的,他的意思是InterlockedExchange仅用于y)。

4

4 回答 4

1

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

作为第二点,应该注意的是,存储并不总是全局可见的,它们只有在序列化时才可见,无论是通过栅栏还是总线锁。

于 2011-10-07T11:10:50.913 回答
0

对于您观察到的矛盾,有两个看似合理的解决方案。

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

另一个是在该特定示例中实际上可能不需要额外的互锁,因为这是一种非常特殊的情况:仅更改了变量的一位。但是,正在开发的规范似乎没有将此作为前提,所以我怀疑这是故意的。

于 2011-10-08T22:44:08.540 回答
0

您只需使用InterlockedExchange. 为什么你需要它?原因InterlockedExchange做了两件事。

  1. 替换变量的值
  2. 返回旧值

如果您在 2 个操作中执行相同的操作(因此首先检查值然后替换),如果在这 2 个操作之间发生其他指令(在另一个线程上),您可能会被搞砸。

而且您还可以防止此值上的数据竞争。在这里您可以很好地解释为什么在 LONG 上读/写不是原子的

于 2011-10-07T11:10:16.340 回答
0

我认为这个讨论可以回答这个问题:隐式记忆障碍

问题:在 T1 和 T2 上调用 InterlockedExchange(隐式全围栏)是否意味着 T2 将“看到”T1 在围栏之前完成的写入?(A、B 和 C 变量),即使这些变量与 Foo 和 Bar 不在同一缓存行上?

回答:是的——由 InterlockedExchange 生成的完整栅栏将保证对 A、B 和 C 的写入不会重新排序超过 InterlockedExchange 调用中隐含的栅栏。这是内存屏障语义的重点。它们不需要位于同一缓存行上。

内存屏障:软件黑客的硬件视图以及Xbox 360 和 Microsoft Windows的无锁编程注意事项也很有趣。

于 2011-10-19T10:24:03.043 回答