While doing concurrent programming I need to tell the compiler/optimizer that it may not cache the value of a variable, that is, it may change at any time. I am currently using the volatile keyword, but I am wondering if this is actually correct?
The standard states that volatile accesses may not be reordered, like IO calls, but I actually don’t care about the ordering at all, I care about the contents. Is there anything in the standard that would clarify that a volatile must be loaded every time it is accessed?
More so, in this case I don’t even care if it is reordered. I use fences/atomic operations to guarantee any ordering which I need.
Also, in C++0x, will using atomic<T> automatically give this same loading guarantee (if I call load)? Or will I nonetheless have to mark the variable as volatile?
IMPORTANT I’m not interested in locking a section of code. I already use fences to ensure ordering. I’m talking specifically about the access to a single fundamental like int (assume atomic on the platform I’m on). That is, I need to specifically tell the GCC optimizer that variable a should not be cached in any way, so that if used in a loop the appropriate load instruction must be called every single time.
If volatile is not correct, what is the correct way of doing this? I am using GCC and not using C++0x at the moment.
ANSWER: Basically pre C++0x there is nothing to force a reload, and reload may not even be enough on certain architectures. volatile strongly implies that the variable should be reloaded, and will work on many architectures, and while not the correct answer, is the only available option at the moment.
There are already many questions about volatile, but I have not seen one that addresses specifically what I am asking: the proper way to mark a variable for concurrent access.
Congratulations on figuring so many details out for yourself. Yes,
volatileis not particularly useful for multithreaded programming, and constructs provided by your platform-specific multithreading library (e.g. pthreads) should always be preferred.Specifically, you should use a read-write lock: an object which can be unlocked for one writer at a time to the exclusion of readers and other writers, or unlocked by multiple readers to the exclusion of any writer. This will be included in any threading API.
C++0x
atomic<T>does solve the problem, you should never needvolatileunless you are writing a device driver. Howeveratomicis at a lower level and you’ll probably be better off with the read-write lock abstraction.