Here are some other places where volatile is appropriate:
1. Reading or writing shared memory
2. Values which may be modified in signal handlers
3. Implementing atomic types (e.g. boost::atomic)
4. RCU (e.g. ACCESS_ONCE in Linux kernel)
1. Reading or writing shared memory
2. Values which may be modified in signal handlers
3. Implementing atomic types (e.g. boost::atomic)
4. RCU (e.g. ACCESS_ONCE in Linux kernel)
Really you should be using the appropriate platform memory and execution barriers in place of volatile 99% of the time.
An illustration:
static volatile sig_atomic_t interrupted = 0;
void sigint_handler(int s) { interrupted = 1; }
void run()
{
signal(SIGINT, sigint_handler);
for (;;)
{
if (interrupted) break;
stuff();
}
}
"volatile" is the most precise way to prevent the compiler from hoisting the 'interrupted' access out of the loop. Memory barriers aren't necessary, because the code is single threaded. They may effectively defeat the optimization too, but it's by confusing the compiler instead of informing it.edit: Oh, and std::atomic is a very bad solution to the above. std::atomic may take locks, which can lead to a deadlock if used in a signal handler!
Yeah I was bit by that when writing a shared memory low latency library. When compiled under debug it worked, in release mode values were not being written to the shared memory area. Added some "volatile"-s in there and it worked.