【发布时间】:2019-11-20 12:06:40
【问题描述】:
#include <atomic>
#include <cassert>
#include <thread>
std::atomic<bool> x = false, y = false, go = false;
int v = 0;
// t1
void write_xy() {
while (!go) {
std::this_thread::yield();
}
v = 1; // 1
x.store(true, std::memory_order_relaxed); // 2
y.store(true, std::memory_order_relaxed); // 3
}
// t2
void read_yx() {
while (!go) {
std::this_thread::yield();
}
while (!y.load(std::memory_order_relaxed))
;
assert(1 == x.load(std::memory_order_relaxed)); // 4
assert(1 == v); // 5
}
int main() {
for (;;) {
x = false;
y = false;
v = 0;
go = false;
std::thread t1(write_xy);
std::thread t2(read_yx);
go = true; // start
t1.join();
t2.join();
}
}
作为一个C++并发编程的初学者,根据我对memory_order_relaxed的理解,上面代码中t1线程中的三个语句的执行顺序对于t2是不可见的。从t2的角度来看,t1中的三个语句的顺序可能是3、2、1,所以4和5处的assert可能会触发。
经过多次尝试,assert 始终没有触发,所以我编写了一个无限循环重复上述过程,assert 仍然没有触发。后来怀疑t1在t2开始执行之前就结束了,所以引入go变量在两个线程开始时等待,保证两个线程尽快开始执行,而assert仍然没有触发。
我在使用 Centos8 和 4 个 CPU 的虚拟机上进行测试。我的 CPU 是 i5-7500。
【问题讨论】:
-
AFAIK,x86-64 不支持
memory_order_relaxed商店的硬件。所有商店都是发布商店。在汇编级别,x.store(true, std::memory_order_relaxed)和x.store(true, std::memory_order_release)之间没有区别。 -
某事没有发生并不意味着它不会发生。有太多的参数在这里起作用。例如,IIRC、x64 无法重新排序加载-加载或存储-存储操作。因此,如果它们没有被编译器重新排序,它就不会在运行时发生。但这并不适用于所有架构。
标签: c++ multithreading concurrency