At the assembly level, barriers are not required in many cases because x86 have total-store ordering. There are a few cases where memory-barriers are still needed... but not nearly as many examples as in ARM-world.
At the C / C++ level, barriers are required because almost all compilers rearrange code in the name of optimization (especially as you go from -O to -O1, to -O2, to -O3... more aggressive rearrangements happen).
The optimizer needs to know "not" to rearrange some code, so a compiler barrier is needed.
---------
It turns out that a compiler barrier (hey compiler: do not rearrange this read/write I'm specifying) is identical in concept to a CPU-memory barrier on a weak-ordered system (hey CPU: don't reorder this read/write I'm specifying).
At the C / C++ level, barriers are required because almost all compilers rearrange code in the name of optimization (especially as you go from -O to -O1, to -O2, to -O3... more aggressive rearrangements happen).
The optimizer needs to know "not" to rearrange some code, so a compiler barrier is needed.
---------
It turns out that a compiler barrier (hey compiler: do not rearrange this read/write I'm specifying) is identical in concept to a CPU-memory barrier on a weak-ordered system (hey CPU: don't reorder this read/write I'm specifying).