mardi 25 janvier 2022

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

I am trying to learn about execution order involving atomic variables in C++, and I have the following code.

According to cppreference, I have the following reasoning:

  1. C++ enforce 1->2 order when executing Because no load/store can be moved before an acquire-load within the same thread.

  2. C++ enforce 3->4 order when executing The same reason as 1

  3. C++ enforce 2->3 order when executing

    Because 2 is a release-store to y, and 3 is an acquire-load from y. So 2 should be visible to 3. Thus, 2 should be executed before 3, and 3 will read the result of 2's write.

  4. C++ enforce 4->1 order when executing The same reason as 3

From reasoning 1/2/3, we can deduce a execution order of 1 -> 2 -> 3 -> 4, and it will break reasoning 4. From reasoning 1/2/4, we can deduce a execution order of 3 -> 4 -> 1 -> 2, and it will break reasoning 3.

Seems there are conflicts here.

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());
    }
}

-- EDIT --

My reasoning about why 2 must happens before 3:

  1. From preshing, y.store(rel) syncs-with y.load(acq).
  2. Then according to cppreference, we can have y.store(rel) Inter-thread happens-before y.load(acq).
  3. Then y.store(rel) happens-before y.load(acq).
  4. So y.store(rel) must happens before y.load(acq)

Aucun commentaire:

Enregistrer un commentaire