C++中的 |= 运算符在多核处理器上是否具有原子性?

4

我目前正在与另一位开发者辩论,他向我保证以下 C++ 语句是原子性的:

x |= 0x1; // x is shared by multiple threads

使用VC++11在发布模式下编译,将生成以下汇编代码:

01121270  or          dword ptr ds:[1124430h],1

另一位开发者说位运算是原子操作,因此线程安全。但我的经验表明,在英特尔i7处理器上不是这样的。
我以为在多核处理器上,任何共享内存写入都是不安全的,因为每个处理器缓存都是独立的。但是,经过更多的研究,似乎x86处理器在处理器/核之间的内存操作顺序方面提供了一些保证,这表明它应该是安全的……但根据我的经验,这似乎并不是这种情况。
由于我没有权威的知识,很难为自己辩护,甚至难以确定自己是正确的。

2
这只是与平台相关的问题,不是吗?我认为你应该指定你的平台。 - ikh
2
一些编译器可能会在某些架构上生成线程安全的代码,但并不保证。使用std::atomic<int>也没有任何缺点,它具有保证原子性的operator|=,因此您应该这样做。 - Wintermute
我相当确定,在x86架构中,需要使用“lock”指令前缀来确保在多个处理器/内核情况下的原子性。也就是说,它必须是lock or dword ptr ds:[11224430h],1。但我手头没有参考资料。如果你使用std::atomic <int>,它会编译成什么? - davmac
请参考例如https://dev59.com/-nA75IYBdhLWcg3wW3oZ。 - davmac
使用 std::atomic<uint32_t> 确实会在或操作中添加“锁定”。std::atomic 的缺点是它仅适用于 c++11。 - Robert Smith
显示剩余4条评论
1个回答

8
不,这绝对不能保证是原子的。它是否使用不可中断的指令(序列)来实现取决于编译器和平台。但从标准的角度来看,它不是原子性的;因此,如果一个线程执行了x |= 0x1;,另一个线程在之间没有同步点地访问了x,那么就会出现未定义的行为(数据竞争)。
C++11中支持的引用:
1.10/5:
库定义了一些特别标识为同步操作的原子操作(Clause 29)和互斥量(Clause 30)...。
第29条介绍了std::atomic和相关函数。 它不将基本类型指定为原子类型。
1.10/21:
如果程序同时包含两个不同线程执行的冲突操作(至少其中一个不是原子操作),且两者都不在对方之前发生,则程序的执行将存在数据竞争。任何这样的数据竞争都会导致未定义的行为。...

谢谢,我有这种感觉,但没有自信去肯定它。 - Robert Smith
@RobertSmith 为了记录,"冲突操作"和"发生在之前"也在1.10中有明确定义,但我不想复制整个章节的一半。 - Angew is no longer proud of SO

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接