Because volatile variables are not atomic variables. The only point in using volatile
is to prevent possible compiler optimisations, which is not the same as preventing unwanted concurrent access.
In that regard, the use of volatile
is almost never correct.
You can read more about it in Semantics and Behavior of Atomic and Bitmask Operations.
Quoting a small part of it:
* WARNING: atomic_read() and atomic_set() DO NOT IMPLY BARRIERS! *
Some architectures may choose to use the volatile keyword, barriers, or inline
assembly to guarantee some degree of immediacy for atomic_read() and
atomic_set(). This is not uniformly guaranteed, and may change in the future,
so all users of atomic_t should treat atomic_read() and atomic_set() as simple
C statements that may be reordered or optimized away entirely by the compiler
or processor, and explicitly invoke the appropriate compiler and/or memory
barrier for each use case. Failure to do so will result in code that may
suddenly break when used with different architectures or compiler
optimizations, or even changes in unrelated code which changes how the
compiler optimizes the section accessing atomic_t variables.
* YOU HAVE BEEN WARNED! *