← Concepts

阅读中文版本

Happens-Before Relationship

The happens-before relation defines which memory writes a thread is guaranteed to observe, and it is the foundation of every correct memory model reasoning.

concurrency

Definition

Happens-before is a partial ordering between memory operations such that if one operation happens before another, every side effect of the first is visible to the second.

Context and scope

It is invoked whenever reasoning about whether one thread's writes are seen by another, including via locks, volatile variables, and atomic operations.

Common misconceptions

  • program order alone guarantees visibility across threads
  • happens-before requires a physical time ordering

Anti-patterns

  • sharing mutable data without a synchronising edge
  • assuming a compiler or CPU will not reorder independent accesses

Related concepts

Authoritative source

https://en.cppreference.com/w/cpp/atomic/memory_order

Definition

Happens-before is a partial ordering between memory operations such that if one operation happens before another, every side effect of the first is visible to the second.

It is invoked whenever reasoning about whether one thread’s writes are seen by another, including via locks, volatile variables, and atomic operations. Compared to simpler alternatives, this concept fits best when the trade-off it represents is the one the system actually cares about.

When to use it

A common use case is applying it at the boundary where the cost of getting it wrong is highest, and the scenario usually involves a concrete guarantee the system must uphold. Unlike an ad hoc approach, it makes that guarantee explicit, reviewable, and testable.

How it works

A lock release and its matching acquire create a happens-before edge, so writes made before the release are visible to any thread that later acquires the same lock.

Without such an edge, the compiler and CPU may reorder or cache writes, so two threads can disagree about memory even when the program order appears correct.

Trade-offs and alternatives

Language memory models define the edges precisely: volatile writes, atomic operations with appropriate ordering, and thread start and join all establish happens-before. The main drawback is the extra complexity it introduces, so the benefit should clearly outweigh that cost before a team adopts it.

Common misconceptions

A persistent misconception is that program order alone guarantees visibility across threads. Another is that happens-before requires a physical time ordering. For example, an engineer who assumes otherwise may design around a guarantee that does not actually exist, which only becomes obvious under load or failure.

Anti-patterns to avoid

Two recurring anti-patterns are to sharing mutable data without a synchronising edge and to assuming a compiler or CPU will not reorder independent accesses. Both tend to surface as hard-to-debug production issues rather than obvious test failures. Related concepts include Thread-Local Storage, Asynchronous I/O, Goroutine and Task Leaks.