Aditya Sihag Aditya Sihag - 19 days ago 8
C++ Question

fetch_add with acq_rel memory order

Consider an

std::atomic<int> x(0);


Let's suppose I have a function doing the following:

int x_old = x.fetch_add(1,std::memory_order_acq_rel);


Based on the description for acquire release memory ordering:


memory_order_relaxed Relaxed operation: there are no synchronization or ordering constraints, only atomicity is required of this operation (see Relaxed ordering below)

memory_order_consume A load operation with this memory order performs a consume operation on the affected memory location: no reads or writes in the current thread dependent on the value currently loaded can be reordered before this load. Writes to data-dependent variables in other threads that release the same atomic variable are visible in the current thread. On most platforms, this affects compiler optimizations only (see Release-Consume ordering below)

memory_order_acquire A load operation with this memory order performs the acquire operation on the affected memory location: no reads or writes in the current thread can be reordered before this load. All writes in other threads that release the same atomic variable are visible in the current thread (see Release-Acquire ordering below)

memory_order_release A store operation with this memory order performs the release operation: no reads or writes in the current thread can be reordered after this store. All writes in the current thread are visible in other threads that acquire the same atomic variable (see Release-Acquire ordering below) and writes that carry a dependency into the atomic variable become visible in other threads that consume the same atomic (see Release-Consume ordering below).

memory_order_acq_rel A read-modify-write operation with this memory order is both an acquire operation and a release operation. No memory reads or writes in the current thread can be reordered before or after this store. All writes in other threads that release the same atomic variable are visible before the modification and the modification is visible in other threads that acquire the same atomic variable.

memory_order_seq_cst Any operation with this memory order is both an acquire operation and a release operation, plus a single total order exists in which all threads observe all modifications in the same order (see Sequentially-consistent ordering below)


Is it possible for 2 distinct threads to receive the same
x_old
value of 0? Or are they guaranteed to execute in a manner that
x_old
is 0 for only one of them, and is 1 for the other.

If it is true that
x_old
could be 0 for both of them, does changing the memory ordering to
std::memory_order_seq_cst
guarantee uniqueness of
x_old
?

Answer

Is it possible for 2 distinct threads to receive the same x_old value of 0?

It is not possible because the operation is atomic. It either happens in full, or not happen at all.

Ordering is concerned with preceding/following loads/stores and since you do not have any, ordering is irrelevant here. In other words, x.fetch_add(1, std::memory_order_relaxed); has the same effect here.

On current x86 is it the same lock add instruction regardless of memory_order, lock prefix provides both atomicity and ordering. For memory_order_relaxed the ordering part is unnecessary.