使用 seq_cst 内存顺序,以下代码永远不应该有 v1 == 0 和 v2 == 2 。但它仍然只是在我的 Apple M1 芯片上打印
Reorder happened
。我真的不知道为什么。
#include <semaphore.h>
#include <cstdio>
#include <atomic>
#include <thread>
std::atomic<int> v1, v2;
sem_t start_1, start_2, complete;
int main() {
sem_init(&start_1, 0, 0);
sem_init(&start_2, 0, 0);
sem_init(&complete, 0, 0);
std::thread t1([&] {
while (true) {
sem_wait(&start_1);
v1.store(1, std::memory_order_seq_cst);
asm volatile("":: : "memory");
v2.store(2, std::memory_order_seq_cst);
sem_post(&complete);
}
});
std::thread t2([&] {
while (true) {
sem_wait(&start_2);
int val1 = v1.load(std::memory_order_seq_cst);
asm volatile("":: : "memory");
int val2 = v2.load(std::memory_order_seq_cst);
if (val1 == 0 && val2 == 2) {
puts("Reorder happened");
}
sem_post(&complete);
}
});
for (int i = 0; i < 1000000; i++) {
v1 = v2 = 0;
sem_post(&start_1);
sem_post(&start_2);
sem_wait(&complete);
sem_wait(&complete);
}
t1.detach();
t2.detach();
return 0;
}
这些值可以通过线程之间程序操作顺序的简单交错来解释。
seq_cst
StoreStore 或 LoadLoad 的正确试金石需要以与存储相反的顺序加载,并在第 2 个加载结果中看到
v1.load gets 0
both stores in order
v2.load gets 2
,第一个加载结果中非零。
但即使使用0
进行此测试,您也可能不会看到此类重新排序,因为两个变量可能最终位于同一缓存行中,因此 CPU 没有理由对它们重新排序。 特别是因为两个加载地址同时准备好。 请参阅 C++ 原子变量内存顺序问题无法重现 LoadStore 重新排序示例
,了解有关 C++ 和您所针对的 ISA 允许的内存重新排序效果的实际演示的一些建议。 相关的不完全重复:无法让 C++ 的 seq_cst 内存模型工作 - 构造不良的石蕊测试的另一种情况,其中所谓有趣的结果可能会发生在 relaxed
中。 那是为了 IRIW 重新排序。