
An object that has volatile-qualified type may be modified in ways unknown to the implementation or have other unknown side effects. Asynchronous signal handling, for example, may cause objects to be modified in a manner unknown to the compiler. Without this type qualifier, unintended optimizations may occur. These optimizations may cause race conditions because a programmer may write code that prevents a race condition, yet the compiler is not aware of the programmer's data model and may modify the code during compilation to permit race conditions.
The volatile
keyword eliminates this confusion by imposing restrictions on access and caching. According to the C99 Rationale [ISO/IEC 2003],
No caching through this lvalue: each operation in the abstract semantics must be performed (that is, no caching assumptions may be made, because the location is not guaranteed to contain any previous value). In the absence of this qualifier, the contents of the designated location may be assumed to be unchanged except for possible aliasing.
Type qualifying objects as volatile does not guarantee synchronization between multiple threads, protect against simultaneous memory accesses, or, unless used to declare objects of type sig_atomic_t
, guarantees atomicity of accesses to the object. For restrictions specific to signal handlers, see SIG31-C. Do not access or modify shared objects in signal handlers.
...
The sig_atomic_t
type is the integer type of an object that can be accessed as an atomic entity even in the presence of asynchronous interrupts. The type of sig_atomic_t
is implementation-defined, though it provides some guarantees. Integer values ranging from SIG_ATOMIC_MIN
through SIG_ATOMIC_MAX
may be safely stored to a variable of the type. In addition, when sig_atomic_t
is a signed integer type, SIG_ATOMIC_MIN
must be no greater than -127
and SIG_ATOMIC_MAX
no less than 127
. Otherwise, SIG_ATOMIC_MIN
must be 0
and SIG_ATOMIC_MAX
must be no less than 255. The macros SIG_ATOMIC_MIN
and SIG_ATOMIC_MAX
are defined in the header <stdint.h>
.
...
Note, however, that declaring an object volatile is not sufficient to prevent data races when the object is simultaneously accessed from within two or more threads of execution. Additional memory visibility constraints may necessitate the use of platform-specific constructs such as memory barriers, for example, when each of the threads runs on a different processor. See CON02-C. Do not use volatile as a synchronization primitive for more information.
...
Bibliography
[ISO/IEC 2003] | Section 6.7.3, "Type Qualifiers" |
---|---|
[ISO/IEC 9899:2011] | Section 6.7.3, "Type Qualifiers," and section 7.14, "Signal Handling <signal.h> " |
[Sun 2005] | Chapter 6, "Transitioning to ISO C" |
...