如何用 acq/rel 顺序推导出两个变量 store/load 的顺序?

How to deduce order of two variables store/load with acq/rel order?

我正在尝试了解 C++ 中涉及原子变量的执行顺序,并且我有以下代码。

根据cppreference,我有以下推理:

  1. C++ 在执行时强制执行 1->2 顺序 因为在同一线程内的获取加载之前不能移动 load/store。

  2. C++ 在执行时强制执行 3->4 顺序 和1

    一样的道理
  3. C++ 在执行时强制执行 2->3 顺序

    因为 2 是对 y 的发布存储,而 3 是对 y 的获取加载。 所以 2 应该对 3 可见。 因此,2应该先于3执行,3会读取2的写入结果。

  4. 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 之前的推理:

  1. 从 preshing 开始,y.store(rel) 与 y.load(acq) 同步。
  2. 那么根据cppreference,我们可以有y.store(rel) Inter-thread happens-before y.load(acq).
  3. 然后 y.store(rel) 发生在 y.load(acq) 之前。
  4. 所以 y.store(rel) 必须发生在 y.load(acq)
  5. 之前

1将“发生在”2之前,3将“发生在”4之前。这部分是正确的。

但是,要使 3 与 2“同步”(以及“发生在其后”),它必须成功读取 2 写入的值。

如果它不读取该值(因为它在 2 之前结束 运行),则不会发生同步,并且不会对 4 相对于 1 强加任何顺序。在这种情况下,表示 3成为 "coherence-ordered before" 2.

同样适用于 1 从 4 读取值。