Consider the following spin_lock()
implementation, originally from this answer:
void spin_lock(volatile bool* lock) {
for (;;) {
// i
This important: in C++ volatile
has nothing at all to do with concurrency! The purpose of volatile
is to tell the compiler that it shall not optimize accesses to the affected object. It does not tell the CPU anything, primarily because the CPU would know already whether memory would be volatile
or not. The purpose of volatile
is effectively to deal with memory mapped I/O.
The C++ standard is very clear in section 1.10 [intro.multithread] that unsynchronized access to an object which is modified in one thread and is accessed (modified or read) in another thread is undefined behavior. The synchronization primitives avoiding undefined behavior are library components like the atomic classes or mutexes. This clause mentions volatile
only in the context of signals (i.e., as volatile sigatomic_t
) and in the context of forward progress (i.e., that a thread will eventually do something which has an observable effect like accessing a volatile
object or doing I/O). There is no mention of volatile
in conjunction with synchronization.
Thus, unsynchronized assess to a variable shared across threads leads to undefined behavior. Whether it is declared volatile
or not doesn't matter to this undefined behavior.