So I’ve read a bunch of articles, both here on SO, and elsewhere, on the topic of shared variables, multiple threads and volatile.
If you consider the following code:
class C {
int x;
public:
C() : x(0) { }
void Operation() {
AcquireMutex();
++x;
ReleaseMutex();
}
};
Now, if I have understood everything I’ve read so far, this would be a correct way to update x, right? A correct compiler will not reorder the code, to cache the value of x before the call to AcquireMutex(), right?
I’ve always had a habit of tagging such variables with volatile. Something I picked up in school way back when dinosaurs roamed the lands, and never really reflected on it. After reading articles on the topic, it would seem that I have wasted a few minutes of my life typing out a (for these types of uses) useless keyword…
UPDATE:
Ok, so if I change Operation() to this instead:
void Operation() {
AcquireMutex();
++x;
ReleaseMutex();
AcquireMutex();
++x;
ReleaseMutex();
}
Now, let’s disregard the use of mutexes, and intrinsics such as InterlockedIncrement(), or whatever. It is kind of besides my point.
If x is not marked as volatile, will the code above be thread safe? Could it be that a compiler decides to hold the last value of x in a register after the first increment, and then just increment the register’s value, and store that in memory at the last increment? If that is the case, then the code above is not thread safe. What gives? Will the compiler assume that after a call to any function, all cached variables are considered “dirty”, thus forcing the compiler to issue read operations?
volatilesays nothing about atomicity. Its purpose is to prevent caching of memory locations that should not be cached (e.g., hardware device DMA ports.) (EDIT: This wording was in reference to “caching” by the generated code. For example, a non-volatilevariable might be read from memory, then kept in a register indefinitely. Arkadiy offered a more precise definition in a comment, below.)And as others have noted, no operation in C or C++ is guaranteed to be atomic. You’re on your own to manage mutexes or other guards as needed.