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
- The "writer" thread writes to an
atomic_uint(with any memory order qualifier, from memory_order_relaxed to memory_order_seq_cst) - The "reader" thread does an atomic relaxed read on the same
atomic_uint
Solution 2
- The "writer" thread writes to a
volatile unsigned int - 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?
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
0xAAAAAAAAor0xBBBBBBBBto a variable, the volatile read could yield0xAAAABBBB. 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.