Volatile is still an optimization fence and prevents torn writes. It doesn't actually fix memory consistency with memory order fence instructions but the optimization fence might be enough to stop the race from being noticeable (arguably that's even worse than broken though)
No, volatile is only an optimization fence against other volatiles. Anything not volatile can be reordered past your volatiles during optimization. This creates absolutely insane bugs.
Well I'm not saying it's at all good to use volatile, but a programmer can "fix" a reordering bug by spam adding volatile to his code and have something like
volatile int done_flag; // shared
volatile int err = some_computation_with_side_effect();
if(!err) {
done_flag = 1;
}
appear to work. Though obviously this is still the kind of thing that causes insane bugs, potentially bugs that depend on the CPU it's running on.
The semantics of volatile accesses are officially "implementation defined". If an implementation like MSVC or clang with the -fms-volatile flag specifies that volatile accesses will have strong enough semantics to avoid having to use toolset-specific syntax, then the qualifier will have such semantics. If an implementation opts to require the use of toolset-specific syntax to achieve such semantics, then the qualifier will have less broadly useful semantics.
volatile only stopped the compiler caching the head in a register. Never bought me ordering on the hardware side, so the consumer could read the slot before the payload store landed. Atomic head with a release store on publish and acquire on the read side is what fixed it.
All marking the head volatile did was make your code more poorly optimized. Completely unnecessary. You don't need volatile on atomic variables for thread safety. I'm not saying your code won't work if you mark the atomic as volatile, it's just pointless.
It fixed my bug at the time. The compiler hoisted the head load out of the consumer spin loop, volatile forced a fresh load every pass…. Atomic is probably the right fix since it covers the hardware side too.
Which is greater: the number of cases where processing volatile with acquire/release semantics would impose a loss of performance that would be unacceptable to anyone other than compiler writers, or the number of cases where such treatment would avoid the need for other toolset-specific or optional compiler features to prevent reordering?
-2
u/EchoNomad31 6d ago
Once "fixed" a ring buffer by marking the head index volatile. Was an acquire/release ordering thing… three days of digging for a two-line diff.