多个线程能否安全地将相同的值同时写入同一个变量?

Can multiple threads write the same value to the same variable at the same time safely?

多个线程能否安全地同时向同一个变量写入相同的值?

举个具体的例子——C++ 标准是否保证以下代码在每个符合标准的系统上编译 运行 没有未定义的行为并打印 "true"?

#include <cstdio>
#include <thread>

int main()
{
    bool x = false;
    std::thread one{[&]{ x = true; }};
    std::thread two{[&]{ x = true; }};
    one.join();
    two.join();
    std::printf(x ? "true" : "false");
}

这是一道理论题;我想知道它是否肯定总是有效,而不是它在实践中是否有效(或者像这样编写代码是否是个好主意:))。如果有人能指出标准的相关部分,我将不胜感激。根据我的经验,它在实践中总是有效,但不知道它是否保证有效我总是使用 std::atomic 代替 - 我想知道对于这种特定情况这是否是绝对必要的。

没有

您需要同步对这些变量的访问,通过使用互斥或​​使它们成为原子。

写入相同值时没有豁免。您不知道编写该值涉及哪些步骤(这是潜在的实际问题),标准也不知道,这就是代码具有未定义行为的原因……这意味着您的编译器可以对您的程序造成绝对混乱(这就是您需要避免的 真实 问题)。

有人会告诉您某某架构可以保证原子写入这些大小的变量。但这并没有改变 UB 方面。

您要查找的段落是:

[intro.races/2]: Two expression evaluations conflict if one of them modifies a memory location ([intro.memory]) and the other one reads or modifies the same memory location.

[intro.races/21]: […] The execution of a program contains a data race if it contains two potentially concurrent conflicting actions, […]. Any such data race results in undefined behavior.

...以及周围的措辞。该部分实际上非常深奥,但您实际上不需要解析它,因为这是经典的教科书数据竞赛,您可以在任何有关编程的书籍中读到它。

亮度是正确的,从标准的角度来看是正确的。

但我会给你另一个观点,为什么从硬件架构的角度来看这不是一个好主意。

如果没有内存屏障(原子、互斥等...),您可能会遇到所谓的缓存一致性问题。在多核或多处理器机器上,您的两个线程都可以将 x 设置为 true,但您的主线程可能会打印 false,即使您的编译器没有隐藏 x 写入寄存器。那是因为主线程使用的硬件缓存还没有更新到 x 从它所在的任何缓存行无效。 C++ 提供的原子类型和锁守卫(以及无数 OS 原语)被实现来解决这个问题。

无论如何,google for Cache Coherence Problem and Cache Coherence Multicore. And for a particular architecture implementation of how atomic transactions are implemented, look up the Intel LOCK prefix.