Acquire Release Semantic
There is no global synchronization between threads in the acquire-release semantic; there is only a synchronization between atomic operations on the same atomic variable. A write operation on one thread synchronizes with a read operation on another thread on the same atomic variable.
The acquire-release semantic is based on one key idea: a release operation synchronizes with an acquire operation on the same atomic and establishes an ordering constraint. This means all subsequent read and write operations cannot be moved before an acquire operation, and all read and write operations cannot be moved after a release operation.
What is an acquire or release operation? The reading of an atomic variable with
test_and_set is an acquire operation. That being said, there is more: the acquiring of a lock, the creation of a thread, or waiting on a condition variable. Of course, the opposite is also true: releasing a lock, the join call on a thread or the notification of a condition variable are release operations. Accordingly, a
clear operation on an atomic variable is a release operation. Acquire and release operations usually come in pairs.
It is worthwhile to think about the last few sentences from a different perspective. The lock of a mutex is an acquire operation, and the unlock of a mutex is a release operation. Figuratively speaking, this implies that an operation
var += 1 cannot be moved outside of a critical section. On the other hand, a variable can be moved inside of a critical section because the variable moves from the non-protected to the protected area.
It helps a lot to keep that picture in mind.