I wish people would not say "undefined behavior" to mean something that looks vaguely iffy or dangerous. It has a pretty specific meaning. [1]
x84/64 has a pretty strong memory model. Bareback sharing of 64-bit variables has pretty much acquire-release semantics. Of course you should still say atomic and acq_rel when you actually mean that, but it's a question of portable code, not UB.
Volatile stops the compiler from shuffling accesses around so that has can affect inter-thread observation order in some cases.
Race conditions are undefined behavior though. It's even included in that post you just linked as an example of undefined behavior.
> There are many other kinds of course, including sequence point violations like "foo(i, ++i)", race conditions in multithreaded programs, violating 'restrict', divide by zero, etc.
x84/64 has a pretty strong memory model. Bareback sharing of 64-bit variables has pretty much acquire-release semantics. Of course you should still say atomic and acq_rel when you actually mean that, but it's a question of portable code, not UB.
Volatile stops the compiler from shuffling accesses around so that has can affect inter-thread observation order in some cases.
[1]: http://blog.llvm.org/2011/05/what-every-c-programmer-should-...