Total Modification Order by Relaxed memory ordering

Here is the Rust code:

static X: AtomicI32 = AtomicI32::new(0);
fn a()
{
      X.fetch_add(5, Relaxed);
      X.fetch_add(10, Relaxed);
}

This code snippet is taken from the Mara Bos's excellent book.
The X is only modified by a thread.

The book says X only has a 0->5->15 modification order. But I think there might be another modification order possible: 0 -> 10 -> 15. The compiler might reorder the instructions--add the 10 first-- in the function a as Relaxed ordering does not ensure the happens-before relationship. This might happen in extremely loosely ordered hardware architecture.

What do you think?

Thanks,

This is explained right before in the book:

While atomic operations using relaxed memory ordering do not provide any happens-before relationship, they do guarantee a total modification order of each individual atomic variable. This means that all modifications of the same atomic variable happen in an order that is the same from the perspective of every single thread.

The relaxed ordering only changes the relationship between X and other variables.

6 Likes

Nit: you meant 0->5->15

1 Like

thanks.

Both fetch_add calls in a() will necessarily be made from a same thread. But for a single thread there's a guarantee (from the book):

The basic happens-before rule is that everything that happens within the same thread happens in order. If a thread is executing f(); g(); , then f() happens-before g() .

So thread A calling a() will always see 0 -> 5 -> 15. Now due to total modification order, all threads must observe the same modification order. Thus, if we know thread A always sees 0 -> 5 -> 15, then everybody else should also see the same order.

There can't be 0 -> 10 -> 15 because thread A can't possibly see that. If compiler were to reorder instructions to really be 0 -> 10 -> 15, other thread could see that and it would differ from thread A. Then the total modification order guarantee would be broken.