Concurrency FundamentalsMemory Models & OrderingHard⏱️ ~3 min

Memory Ordering Modes

Key Insight
C++ offers different memory orderings trading safety for performance. Stronger ordering = more guarantees = slower.
Memory Ordering Spectrum
RELAXEDACQ/RELSEQ_CSTFastestSafestNo orderingguaranteesAcquire/ReleasesemanticsTotal orderall threads

Relaxed (memory_order_relaxed)

Only guarantees atomicity. No ordering constraints. Use for counters where you just need accurate final value, not intermediate visibility.

Acquire/Release

Acquire (on load): No reads/writes after this can be reordered before it. Acquire the lock, then access data.

Release (on store): No reads/writes before this can be reordered after it. Finish with data, then release the lock.

Sequential Consistency (memory_order_seq_cst)

The default and strongest. All threads see all operations in the same order. Easiest to reason about but has highest cost. Most developers should use this.

Advice: Start with seq_cst. Only weaken if profiling shows it is a bottleneck AND you deeply understand the implications.
💡 Key Takeaways
Relaxed ordering: only atomicity, no visibility guarantees. Use only for statistics counters where ordering does not matter.
Acquire: prevents later operations from moving before. Used when loading a flag or lock state.
Release: prevents earlier operations from moving after. Used when storing a flag or releasing a lock.
Acquire/Release pair synchronizes producer and consumer. Producer release store, consumer acquire load.
Sequential consistency (seq_cst): strongest guarantee, all threads agree on order. Default in Java volatile, slowest option.
📌 Examples
1C++ flag pattern: flag.store(true, memory_order_release); ... if (flag.load(memory_order_acquire)) { // data is ready }
2Relaxed counter: counter.fetch_add(1, memory_order_relaxed); // Fine for statistics, not for coordination.
← Back to Memory Models & Ordering Overview