I'm trying to understand how C11 memory model works and wrote two functions containing expressions that conflict
(in the sense of 5.1.2.4(p4)
):
struct my_struct{
uint64_t first;
int64_t second;
} * _Atomic instance;
void* set_first(void *ignored){
uint64_t i = 0;
while(1){
struct my_struct *ms = atomic_load_explicit(&instance, memory_order_acquire);
ms -> first = i++;
atomic_store_explicit(&instance, ms, memory_order_release);
sleep(1);
}
}
void* print_first(void *ignored){
while(1){
struct my_struct *ms = atomic_load_explicit(&instance, memory_order_acquire);
uint64_t current = ms -> first;
char buf[100];
memset(buf, '\0', sizeof(buf));
sprintf(buf, "%" PRIu64 "\n", current);
fputs_unlocked(buf, stdout);
sleep(2);
}
}
And the main function:
int main(void){
struct my_struct tmp = {.first = 0, .second = 0};
atomic_init(&instance, &tmp);
printf("main\n");
pthread_t set_thread;
pthread_create(&set_thread, NULL, &set_first, NULL);
pthread_t print_thread;
pthread_create(&print_thread, NULL, &print_first, NULL);
while(1){
sleep(100);
}
}
So I tried to prove if the program contains no data-races. Here are my thoughts:
We know that a release operation on an atomic object synchronizes with an acquire operation on the object. So
atomic_store_explicit(&instance, ms, memory_order_release);
in theset_first
synchronizes withatomic_load_explicit(&instance, memory_order_acquire)
in theprint_first
.Since the side effect
ms -> first = i++
in theset_first
function appeared before theatomic_store_explicit(&instance, ms, memory_order_release);
in the program text I assumed it is sequenced-before it (This is I'm not sure about, could not find any normative references).Combining bullets
1.
and2.
implies thatms -> first = i++
inter-thread happens beforeatomic_load_explicit(&instance, memory_order_acquire);
so they are in the happens before relationships.Applying the data-race definition we conclude that confliting actions
uint64_t current = ms -> first;
in theprint_first
function andms -> first = i++;
in theset_first
function do not produce data-race.
So the behavior seems to be well-defined.
The doubtful thing is assumed that ms -> first = i++;
sequenced before atomic_store_explicit(&instance, ms, memory_order_release);
because they occurred one before another in the program text.
Is it correct or the program contains data races?