A developer marks a shared flag volatile and drops the atomic, arguing that volatile stops the compiler caching the flag in a register. Say what volatile does guarantee, the three things it does not, and what the correct declaration is.
A developer marks a shared flag volatile and drops the atomic, arguing that volatile stops the compiler caching the flag in a register. Say what volatile does guarantee, the three things it does not, and what the correct declaration is.
Approach: Separate the freedom the compiler has to remove or merge an access from the freedom the hardware has to reorder the memory operations that result.
Volatile guarantees that every read and write appears in the generated code and is never removed or merged, and it guarantees nothing about atomicity, nothing about memory ordering against other objects, and nothing about visibility between cores, so the correct declaration is an atomic with an explicit memory order. The compiler may still reorder a volatile access against a non-volatile one, and the processor may reorder the resulting loads and stores, so a volatile flag can be seen set before the data it is supposed to protect is visible. A volatile access to a 64 bit object is also not guaranteed to be indivisible on every platform, so a torn read is possible where an atomic would be safe. Volatile is the right tool for memory mapped hardware registers and for a variable shared with a signal handler, where the requirement is that the access happens exactly as written.
Follow-up: Where does volatile remain necessary in correct low-latency code, and why can an atomic not replace it there?
Key concepts: volatile, atomicity, memory ordering, torn read.