Search code examples
cmultithreadingconcurrencyc11memory-model

Understanding release sequence and synchronize with in C11


I'm trying to understand memory model and reads 5.1.2.4 Multi-threaded executions and data races and is confused by the release sequence concept defined at 5.1.2.4(p10) as follows:

A release sequence headed by a release operation A on an atomic object M is a maximal contiguous sub-sequence of side effects in the modification order of M, where the first operation is A and every subsequent operation either is performed by the same thread that performed the release or is an atomic read-modify-write operation.

which is subsequently used to define synchronize with at 5.1.2.4(p11) as follows:

Certain library calls synchronize with other library calls performed by another thread. In particular, an atomic operation A that performs a release operation on an object M synchronizes with an atomic operation B that performs an acquire operation on M and reads a value written by any side effect in the release sequence headed by A.

I can imagine the following example:

#include <stdatomic.h>
Atomic_ int a; // <<--- M

int main(void){
    atomic_store_explicit(&a, 42, memory_order_release); // <<--- A
    atomic_store_explicit(&a, 442, memory_order_release); 
    atomic_store_explicit(&a, 242, memory_order_release); 
    int a_value = atomic_load_explicit(&a, memory_order_acquire);
    atomic_store_explicit(&a, 242, memory_order_release);
}

I currently understands it as A being atomic_store_explicit(&a, 42, memory_order_release); and its release sequence is

atomic_store_explicit(&a, 442, memory_order_release); 
atomic_store_explicit(&a, 242, memory_order_release); 

But atomic_store_explicit(&a, 242, memory_order_release); is not included since it is followed by int a_value = atomic_load_explicit(&a, memory_order_acquire); which is an acquire operation.

Now coming to the synchronize with an atomic operation A that performs a release operation on an object M synchronizes with an atomic operation B that performs an acquire operation on M and reads a value written by any side effect in the release sequence headed by A. means that the all release opearations in the release sequence of A are visible by an acquire operation which is atomic_load_explicit(&a, memory_order_acquire);

Is it correct or I missed something?


Solution

  • No, the sequence includes all four store operations, because the intermediate load operation is done by the same thread. Basically for your example you don't have to refer to synchronization. Since there is only one thread in the game, "sequenced before" already give you all the information that you want. An optimizer could even ommit all stores but the last one in your simplified example, even for atomic operations. (Well there is the volatile in the specification of atomic_store, but let's forget about this for the moment.)

    I think, the idea of the concept of a release sequence is to identify the points at which reads of different threads may intercept stored values, and which make the read dependeny-ordered after the first store operation in the sequence. For that, the fact that the thread reads the value it has written can be ignored.