如何用 acq/rel 顺序推导出两个变量 store/load 的顺序?
How to deduce order of two variables store/load with acq/rel order?
我正在尝试了解 C++ 中涉及原子变量的执行顺序,并且我有以下代码。
根据cppreference,我有以下推理:
C++ 在执行时强制执行 1->2 顺序
因为在同一线程内的获取加载之前不能移动 load/store。
C++ 在执行时强制执行 3->4 顺序
和1
一样的道理
C++ 在执行时强制执行 2->3 顺序
因为 2 是对 y 的发布存储,而 3 是对 y 的获取加载。
所以 2 应该对 3 可见。
因此,2应该先于3执行,3会读取2的写入结果。
C++ 在执行时强制执行 4->1 顺序
同理3
由推理1/2/3推导出执行顺序1 -> 2 -> 3 -> 4
,将打破推理4。
从推理1/2/4,我们可以推导出3 -> 4 -> 1 -> 2
的执行顺序,这将打破推理3.
这里好像有冲突
int main() {
while(true) {
std::atomic<int> x, y;
x.store(10);
y.store(20);
auto f1 = [&]() {
int r1 = x.load(std::memory_order_acquire); // 1
y.store(r1, std::memory_order_release); // 2
};
auto f2 = [&]() {
int r2 = y.load(std::memory_order_acquire); // 3
x.store(r2, std::memory_order_release); // 4
};
std::thread t1(f1);
std::thread t2(f2);
t1.join();
t2.join();
printf("%d %d\n", x.load(), y.load());
}
}
-- 编辑--
我关于为什么 2 必须发生在 3 之前的推理:
- 从 preshing 开始,y.store(rel) 与 y.load(acq) 同步。
- 那么根据cppreference,我们可以有y.store(rel) Inter-thread happens-before y.load(acq).
- 然后 y.store(rel) 发生在 y.load(acq) 之前。
- 所以 y.store(rel) 必须发生在 y.load(acq)
之前
1将“发生在”2之前,3将“发生在”4之前。这部分是正确的。
但是,要使 3 与 2“同步”(以及“发生在其后”),它必须成功读取 2 写入的值。
如果它不读取该值(因为它在 2 之前结束 运行),则不会发生同步,并且不会对 4 相对于 1 强加任何顺序。在这种情况下,表示 3成为 "coherence-ordered before" 2.
同样适用于 1 从 4 读取值。
我正在尝试了解 C++ 中涉及原子变量的执行顺序,并且我有以下代码。
根据cppreference,我有以下推理:
C++ 在执行时强制执行 1->2 顺序 因为在同一线程内的获取加载之前不能移动 load/store。
C++ 在执行时强制执行 3->4 顺序 和1
一样的道理C++ 在执行时强制执行 2->3 顺序
因为 2 是对 y 的发布存储,而 3 是对 y 的获取加载。 所以 2 应该对 3 可见。 因此,2应该先于3执行,3会读取2的写入结果。
C++ 在执行时强制执行 4->1 顺序 同理3
由推理1/2/3推导出执行顺序1 -> 2 -> 3 -> 4
,将打破推理4。
从推理1/2/4,我们可以推导出3 -> 4 -> 1 -> 2
的执行顺序,这将打破推理3.
这里好像有冲突
int main() {
while(true) {
std::atomic<int> x, y;
x.store(10);
y.store(20);
auto f1 = [&]() {
int r1 = x.load(std::memory_order_acquire); // 1
y.store(r1, std::memory_order_release); // 2
};
auto f2 = [&]() {
int r2 = y.load(std::memory_order_acquire); // 3
x.store(r2, std::memory_order_release); // 4
};
std::thread t1(f1);
std::thread t2(f2);
t1.join();
t2.join();
printf("%d %d\n", x.load(), y.load());
}
}
-- 编辑--
我关于为什么 2 必须发生在 3 之前的推理:
- 从 preshing 开始,y.store(rel) 与 y.load(acq) 同步。
- 那么根据cppreference,我们可以有y.store(rel) Inter-thread happens-before y.load(acq).
- 然后 y.store(rel) 发生在 y.load(acq) 之前。
- 所以 y.store(rel) 必须发生在 y.load(acq) 之前
1将“发生在”2之前,3将“发生在”4之前。这部分是正确的。
但是,要使 3 与 2“同步”(以及“发生在其后”),它必须成功读取 2 写入的值。
如果它不读取该值(因为它在 2 之前结束 运行),则不会发生同步,并且不会对 4 相对于 1 强加任何顺序。在这种情况下,表示 3成为 "coherence-ordered before" 2.
同样适用于 1 从 4 读取值。