← Concepts

阅读中文版本

Memory Barrier Ordering

A memory barrier constrains the CPU and compiler from reordering memory operations across it, so that a release store is visible before an acquire load sees it, the foundation of lock-free.

concurrency

Definition

A memory barrier is an instruction that prevents the CPU and compiler from reordering loads and stores across it, so that a store-release publishes data before the flag, and a load-acquire sees the flag only after the data it guards, making the happens-before relationship that lock-free code relies on.

Context and scope

Applied in lock-free algorithms, device driver MMIO, and any code where the memory operation order visible to another core must match the program order.

Common misconceptions

  • A memory barrier makes the program correct — it makes the memory order correct; the program logic still must be correct, and barriers do not fix races
  • Sequentially consistent is always safe — it is safe but slow; weaker orderings (release-acquire) are safe and faster when used correctly

Anti-patterns

  • Using a full barrier where a release or acquire would do, serializing more than necessary and losing performance
  • Forgetting the barrier on a publication pattern, so the flag is seen before the data on a weakly-ordered architecture

Related concepts

Authoritative source

https://preshing.com/20120710/memory-barriers-are-like-source-control-operations/

What it is

A memory barrier is an instruction that prevents the CPU and compiler from reordering loads and stores across it, so that a store-release publishes data before the flag, and a load-acquire sees the flag only after the data it guards, making the happens-before relationship that lock-free code relies on. Applied in lock-free algorithms, device driver MMIO, and any code where the memory operation order visible to another core must match the program order. The central difficulty is that interleaving is nondeterministic: the set of possible executions grows super-exponentially with the number of operations, and testing samples a vanishing fraction.

How it works

Correctness is established by reasoning about happens-before relationships, not by running more tests. Synchronization primitives are chosen for the specific guarantee needed — mutual exclusion, publication, or ordering — and composed only with a documented proof of absence of deadlock. Bounded resources apply backpressure rather than unbounded queuing that hides overload until memory exhausts.

When to apply and pitfalls

Apply whenever multiple flows share mutable state or resources. The dominant pitfall is reasoning sequentially about concurrent code — “this can’t happen because A finishes before B” — when in fact the scheduler can interleave at any instruction boundary. The second is using a coarse lock for simplicity and turning parallelism back into serialization.