C++11 原子是否自动解决变量读写上的多核竞争?

Tro*_*yvs 0 c++ multithreading atomic cpu-cores c++11

我知道atomic<T>当多个线程正在读取和写入变量时,将会对类型“T”变量应用锁定,确保只有其中一个线程正在执行读/写操作。

但在多CPU核心计算机中,线程可以运行在不同的核心上,不同的核心会有不同的L1-cache、L2-cache,同时共享L3-cache。我们知道有时C++编译器会优化将变量存储在寄存器中,这样如果变量没有存储在内存中,那么该变量上的不同core-cache之间就没有内存同步。

如果atomic<T>编译器将变量优化为某个寄存器变量,那么它不会存储在内存中,当一个核心写入其值时,另一个核心可能会读出陈旧的值,对吗?这个数据一致性有保证吗?

Yak*_*ont 5

原子不会按照您模糊描述的方式“解决”问题。它提供了某些非常具体的保证,涉及基于顺序的内存一致性。

不同的编译器在不同的平台上以不同的方式实现这些保证。

在 x86/64 上,对于原子整数和达到合理大小的指针不使用锁。而且硬件提供了比标准要求更强有力的保证,使得一些更深奥的选项相当于完全一致性。

我无法完全回答你的问题,但我可以为你指出正确的方向;你需要学习的主题是“C++内存模型”。

话虽这么说,原子的存在是为了避免您所描述的确切问题。如果您要求完全内存顺序一致性,并且线程 A 修改 X,然后修改 Y,则任何其他线程都不能看到 Y 被修改,但不能看到 X。C++ 标准没有指定如何提供这种保证;缓存行失效、使用特殊指令进行访问、禁止编译器进行某些基于寄存器的优化等都是编译器所做的事情。

请注意,C++ 内存模型针对 C++17 进行了细化、错误修复和完善,以便描述新并行算法的行为,并允许它们在具有正确标志的 GPU 硬件(以及其他位置)上高效实现,进而它影响了新 GPU 硬件提供的保证。因此,谈论内存模型的人们可能会很兴奋,并谈论比您主要关注的 C++11 更现代的问题。

这是一个大而复杂的话题。编写您认为可移植的代码确实很容易,但只能在特定平台上运行,或者通常只能在您测试的平台上运行。但这只是因为线程很难。