Volatile is a confusing keyword. In the C++ standard, volatile is described as a type qualifier, and it is often paired up with const.
But unlike const, volatile actually has side effects. I was told that this keyword is used to disable compiler optimizations, and to replace locks in multi-threading programming.
It sounds like a lot of voodoo involved, but I am rarely given a satisfying explanation. I don’t believe in magic, so I spent some time researching it. In the end, I reached a frightening conclusion.
If you use volatile for multi-threaded programming, you are doing it wrong!
In C++ standard, it says this.
In general, the semantics of volatile are intended to be the same in C++ as they are in C.
That certainly wasn’t informative. So I dug up the C99 standard.
This is the C99 definition of volatile – section 6.7.3 Item 6.
An object that has volatile-qualified type may be modified in ways unknown to the implementation or have other unknown side effects. Therefore any expression referring to such an object shall be evaluated strictly according to the rules of the abstract machine… Furthermore, at every sequence point the value last stored in the object shall agree with that prescribed by the abstract machine…
And for the footnote, it adds this.
A volatile declaration may be used to describe an object corresponding to a memory-mapped input/output port or an object accessed by an asynchronously interrupting function. Actions on objects so declared shall not be “optimized out” by an implementation or reordered except as permitted by the rules for evaluating expressions.
Ideally, to program in a multi-threaded environment, we need a concurrency memory model that addresses atomicity, visibility and memory ordering. In C99 standard, volatile is required to address the issue of visibility, but does nothing to address atomicity and memory ordering.
It’s Not News
It’s funny that once you know what to look for, answers will magically appear out of nowhere.
Since VS8.0, Microsoft decided to go beyond the standard and gave volatile acquire and release semantics. This way, it is actually works like a memory barrier and is useful for multi-threaded programming. This behavior is not portable.
Until C++0x defines a concurrency memory model, use a memory barrier instead of volatile for multi-threaded programming.
C++ pitfalls never cease to amaze me. I think C++FQA needs a new section on volatile.