> No amount of fences or mutexes is going to help you if threads are operating on their own version of a variable that got cached in a register, or optimised away. You need to understand volatile to write correct multi-threaded code.
Any properly written Mutex or similar implementation is going to act as a full memory barrier and compiler barrier, meaning variables will already not be cached across lock/unlock. And if you're not properly taking your locks before accessing your variables, `volatile` is not going to save you. The fact is, if you're using a lock to protect a variable, marking it `volatile` gains you nothing and just slows your code down.
> "yes, to prevent threads from working on stale data".
`volatile` absolutely does not guarantee a variable doesn't contain 'stale' data. That's the entire reason you need memory barriers in the first place. Even through the compiler will read a `volatile` variable from memory every time, that memory may still have a stale value in the CPU cache, which `volatile` will do nothing to prevent. Only proper use of memory barriers ensures everyone is working on the same thing, which `volatile` does not do.
> Even through the compiler will read a `volatile` variable from memory every time, that memory may still have a stale value in the CPU cache, which `volatile` will do nothing to prevent
FWIW, it doesn't even do this, it's just a compiler-level annotation:
volatile int x = 0;
int foo() {
// read
int ret = x;
(void)x;
// write
x = 0;
x = 1;
return ret;
}
The 'volatile' ensures that that code results in two reads and two writes. Removing it allows the compiler to optimise down to the equivalent of 'int ret = x; x = 1; return ret;', but both with and without use the exact same read/write instructions (i.e. have the same interaction with the cache): mov on x86 and ldr/str on ARM.
Nobody's arguing that volatile has anything to do with CPU cache, or barriers, or locks, or any other nonsense! volatile is there to ensure that the compiler generates code that accesses the variable directly each time, which is necessary to write correct multi-threaded code. If you don't use volatile, and your code still works, then either the compiler's smarter than you, or you got lucky. End of story. The level of misunderstanding you guys are showing on the matter is beyond comical.
volatile's one of the simplest modifiers to understand if you care to actually learn the language. It has a clear, and well-defined purpouse, and i have no idea how you can spend so much time, and energy arguing that that's not the case.
> And if you're not properly taking your locks before accessing your variables, `volatile` is not going to save you.
Yes, it will! Just because you’re accessing shared variables doesn’t mean you need locks. This is what volatile is for!
You’re blindly hoping the compiler will do the right thing for you, anyway. You must have little-to-no experience writing multi-theaded code in production, let alone anything more advanced that doesn’t rely on locks.
Nobody’s arguing that volatile somehow bypasses the cache. When it comes to multithreading, that doesn’t matter though, because the whole process works with the cache, and the CPU keeps core caches synchronized. Memory barriers do nothing here.
Any properly written Mutex or similar implementation is going to act as a full memory barrier and compiler barrier, meaning variables will already not be cached across lock/unlock. And if you're not properly taking your locks before accessing your variables, `volatile` is not going to save you. The fact is, if you're using a lock to protect a variable, marking it `volatile` gains you nothing and just slows your code down.
> "yes, to prevent threads from working on stale data".
`volatile` absolutely does not guarantee a variable doesn't contain 'stale' data. That's the entire reason you need memory barriers in the first place. Even through the compiler will read a `volatile` variable from memory every time, that memory may still have a stale value in the CPU cache, which `volatile` will do nothing to prevent. Only proper use of memory barriers ensures everyone is working on the same thing, which `volatile` does not do.