volatile keyword
The purpose of volatile
is to inform the compiler that a value can be changed by something besides the program we're executing. This is particularly important for memory-mapped I/O
, where reads and writes often have read effects on hardware devices.
volatile
guarantees :
- The compiler will not eliminate
loads
andstores
that seem "unnecessary".
For example, *t = 2
is assumed to be dead store
and will be optimized out by the compiler.
void write (int *t) {
*t = 2; // will be optimized out by the compiler.
*t = 42;
}
- The compiler will not reorder
volatile
reads and writes with each other.
Suppose we have the following code:
volatile int reg1;
volatile int reg2;
void main() {
reg1 = 1;
reg2 = 2;
}
The compile will keep the writes in the order given in the source code. It will not swap them.
Volatile does not guarantee atomicity
The rules of volatile
do not provide the atomocity
or ordering
guarantees needed for safe inter-thread communication.
The compiler is still free to rearrange all normal loads and stores around volatile
accesses. For example:
int a = 0;
volatile int flag = 0;
void writer() {
a = 42; // normal store
flag = 1; // volatile store
}
We might expect a
will be set to 42 before flag
is set to 1. However, while the compiler must emit the volatile store to flag and not reorder it with respect to other volatile accesses, it is free to move the non-volatile store to a
around the volatile access.
volatile
does not emit memory barriers on weakly-ordered hardware architectures. It still have chance the hardware itself reordering operations that break multi-threaded synchronization.
Conclusion:
Unless both your compiler and hardware perform no reordering, volatile
is not a reliable mechanism for synchronization between threads.
When to use Volatile Keyword
Accessing MMIO Register
Here are some cases to use volatile[1]
volatile char *ptr = (volatile char *)0x2000000;
printf("value of register is 0x%x", *ptr);