memory_order_relaxed load vs volatile load

1.3k Views Asked by At

What is the difference between reading the value of an atomic_uint with memory_order_relaxed, and reading the value of a volatile unsigned int (assuming the volatile operations are atomic)?

Specifically, let's define:

Solution 1

  1. The "writer" thread writes to an atomic_uint (with any memory order qualifier, from memory_order_relaxed to memory_order_seq_cst)
  2. The "reader" thread does an atomic relaxed read on the same atomic_uint

Solution 2

  1. The "writer" thread writes to a volatile unsigned int
  2. The "reader" thread reads that value

As-is, I know that both cases do not offer any guarantees regarding the ability of the reader to read the value written by the writer. What I'm trying to understand is the difference between the volatile read, and the relaxed atomic read. What does one provide that the other doesn't, when considering read-after-write consistency?

The only difference I see is:

  • volatile operations cannot be re-ordered between them, while the atomic load can be re-ordered with other atomic operations

Is there something else?

2

There are 2 best solutions below

0
On

The use of memory_order_relaxed essentially gives a well behaved volatile variable for the purpose of inter-thread communication:

  • volatile is ultimately specified in term of ABI (Application Binary Interface), it's an external interface; volatiles are interfaces with the external world: an access to such object is part of the observable behavior and cannot ever be optimized away;
  • atomics are well specified purely in term of internal semantics; the representation of objects isn't part of the specification; an access to such object is part of the abstract machine and can sometimes be optimized away, or reasoned with internally (by the compiler, in term of C/C++ semantics).
24
On

The volatile read isn't guaranteed to be atomic. That means you could read a value that was never written to the variable (and also could never be written by any part of your program). E.g. if your application only ever writes 0xAAAAAAAA or 0xBBBBBBBB to a variable, the volatile read could yield 0xAAAABBBB. Or really anything else, since the standard doesn't specify behavior for when volatile reads and writes are appearing in different threads without other means of synchronization.

I don't know if the standard says it's UB or implementation defined though. I can only say that there are implementations (e.g. MSVC 2005) that define behavior for unsynchronized volatile reads/writes as an extension.