Home > Mobile >  On acquire/release semantics not being commutative to other threads
On acquire/release semantics not being commutative to other threads

Time:03-18

The gcc wiki here provides an example on memory ordering constraints.

In the below example, the wiki asserts that, if the memory ordering in use is an acquire/release, then thead-2's assert is guaranteed to succeed while thread-3's assert can fail.

 -Thread 1-       -Thread 2-                   -Thread 3-
 y.store (20);    if (x.load() == 10) {        if (y.load() == 10)
 x.store (10);      assert (y.load() == 20)      assert (x.load() == 10)
                    y.store (10)
                  }

I don't see how that is possible. My understanding is that since Thread-2's y.store(10) synchronizes with Thread-3's y.load() and since y can be 10 if and only if x is 10, I say the assert in Thread-3 should succeed. The wiki disagrees. Can someone explain why?

CodePudding user response:

and since y can be 10 if and only if x is 10,

And that's the part that is incorrect.

An acquire/release pair works between a releasing store operation and an acquiring load operation which reads the value that was release-stored.

In thread 1, we have a releasing store to x. In thread 2, we have an acquiring load from x. If thread 2 read the value stored by thread 1, then the two threads have an acquire/release relationship. What that means is that any values written to other objects in thread 1 before the releasing store are visible to thread 2 after its acquiring load.

In thread 2, we have a releasing store to y. In thread 3, we have an acquiring load from y. If thread 3 read the value stored by thread 2, then the two threads have an acquire/release relationship. What that means is that any values written to other objects in thread 2 before the releasing store are visible to thread 3 after its acquiring load.

But notice what I said: "any values written to other objects in thread 2".

x was not written by thread 2; it was written by thread 1. And thread 3 has no relationship to thread 1.

Pure acquire/release is not transitive. If you need transitive access to memory, then you need sequential consistency. Indeed, that's what seq_cst is for: ensuring consistently across all acquire/releases which transitively rely on each other.

Note that this is primarily about caches. A pure acquire/release operation may only flush certain caches, particularly if the compiler can clearly see exactly what memory a thread is making available in a release.

  • Related