我已阅读文章Synchronization and Multiprocessor Issues ,我对InterlockedCompareExchange和InterlockedExchange有疑问。问题实际上是关于文章中的最后一个例子。他们有两个变量iValue
和fValueHasBeenComputed
,而CacheComputedValue()
他们使用InterlockedExchange
修改每个变量:
InterlockedExchange ((LONG*)&iValue, (LONG)ComputeValue()); // don't understand
InterlockedExchange ((LONG*)&fValueHasBeenComputed, TRUE); // understand
我知道我可以使用InterlockedExchange
来修改iValue
但是它应该只是做
iValue = ComputeValue();
那么实际上是否有必要使用InterlockedExchange
来设置iValue?或者即使iValue = ComputeValue();
,其他线程也会正确地看到iValue。我的意思是其他线程会正确地看到iValue,因为它之后有InterlockedExchange
。
还有论文A Principle-Based Sequential Memory Model for Microsoft Native Code Platforms。有3.1.1示例或多或少相同的代码。其中一个推荐Make y interlocked
。注意 - 不是y
和x
。
更新
只是为了澄清这个问题。问题是我看到了一个矛盾。 “同步和多处理器问题”中的示例使用两个InterlockedExchange
。相反,在示例3.1.1“Basic Reodering”(我认为与第一个示例非常相似)中,Herb Sutter给出了这个推荐
“使y互锁:如果y互锁,则y上没有比赛 因为它是原子可更新的,并且在x上没有竞争,因为a - > b - > d。“
。在这个草案中草药不使用两个互锁变量(如果我是对的,他的意思是仅对InterlockedExchange
使用y
)。
答案 0 :(得分:1)
如果iValue
的地址未与保证原子访问的地址对齐,则他们这样做是为了防止部分读/写。当两个或多个物理线程尝试同时写入值,或者一个读取,一个尝试同时写入时,就会出现此问题。
作为次要点,应该注意的是,商店并不总是全局可见,只有在通过围栏或公共汽车锁进行序列化时才能看到它们。
答案 1 :(得分:0)
您只需使用InterlockedExchange
进行原子操作。你为什么需要它?
因为InterlockedExchange
做了两件事。
如果你在2个操作中执行相同的操作(因此首先检查值然后替换),如果在这2个操作之间发生其他指令(在另一个线程上),则可能会搞砸。
您还可以阻止此值的数据争用。 here你得到一个很好的解释,为什么LONG上的读/写不是原子的
答案 2 :(得分:0)
你所观察到的矛盾有两种看似合理的决议。
一个是第二个文件在这方面是完全错误的。毕竟,这是一份草案。我注意到你所提到的例子明确指出程序员不能依赖写入是原子的,这意味着两个写入必须确实是互锁的。
另一个是在该特定示例中可能实际上不需要额外的互锁,因为它是一种非常特殊的情况:仅改变变量的一个位。但是,正在开发的规范似乎并没有提到这个前提,所以我怀疑这是故意的。
答案 3 :(得分:0)
我认为这个讨论有问题的答案:Implicit Memory Barriers。
问题:在T1上调用InterlockedExchange(隐式全栅栏) 和T2,gurentess T2将“看到”T1之前完成的写入 栅栏? (A,B和C变量),即使这些变量不是 和Foo和Bar在同一个缓存行上一样?
回答:是的 - InterlockedExchange生成的完整围栏将会 保证对A,B和C的写入不会重新排序 在InterlockedExchange调用中隐式的fence。这就是重点 记忆障碍语义。它们不需要位于同一缓存中 线。
Memory Barriers: a Hardware View for Software Hackers和Lockless Programming Considerations for Xbox 360 and Microsoft Windows也很有趣。