I'm trying to understand memory ordering intoduced by atomic_exchange[_explicit]
and wrote the following code:
static _Atomic int i = 123;
void *update(void *ignored){
if(atomic_exchange_explicit(&i, 200, memory_order_release) != 200){ //1
printf("Updated\n", stdout);
}
}
int main(int args, const char *argv[]){
pthread_t t1;
pthread_create(&t1, NULL, &update, NULL);
pthread_t t2;
pthread_create(&t2, NULL, &update, NULL);
sleep(1000);
}
Question: Is it possible the Updated\n
will be printed twice (by both of the threads)?
I think the behavior is undefined. The UB is held even if we replace memory_order_release
with memory_order_acquire
at //1
. The generated code is the same for acq/rel/acq_rel: https://godbolt.org/z/sFjcve .
This is because we have data race since for synchronize with relation to be held we need one operation is an acquire
operation and the next operation is a release
operation and the release operation reads a value written by a side effect from a release sequence of the acquire operation 5.1.2.4(p11)
:
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.
So the only way to make this code's behavior well-defined is to replace atomic_exchange_explicit(&i, 200, memory_order_release) != 200
with atomic_exchange(&i, 200) != 200
You are incorrect. Regardless of the memory ordering requested, the exchange is atomic. Memory ordering explains how this read, write, or read-modify-write operation interacts with other operations, but the operation is always atomic.