Skip to content

The C++ memory model and CAS loops

The C++ Memory Model

Goal: understand "it works on my machine" vs. "correct in theory" (provably correct)


Before C++11

  • No standard concurrency model. pthread/WinAPI were de facto standards, but not part of C++.
  • Compiler/optimizations could break your assumptions: Sharing objects across threads was unconditionally UB. Reordering, caching, dead store elimination.
  • Portable code was hard: Code working on x86 might crash on ARM due to different memory ordering.

After C++11

  • formal, portable concurrency model in the language standard.
  • Defined exactly what the compiler/CPU can and cannot do with memory operations across threads.
  • Made multi-threaded C++ first-class, not just a wrapper around OS APIs.
  • Your code is only "correct" if it conforms to the memory model. If it works without conforming you're relying on stronger hardware guarantees.

Takeaway: The memory model constrains the implementation. This allows C++ users to reason about concurrent behavior.


What Is the C++ Memory Model?

The memory model is the foundation that types like std::thread, std::mutex, or std::atomic rely on.

C++ standard: https://eel.is/c++draft/basic.exec#intro.multithread

Important concepts:

  1. threads of Execution
  2. Reordering & Visibility
    • by the compiler
    • by the CPU/GPU (also cache coherence protocol)
  3. sequenced before
  4. synchronizes with
  5. happens before
  6. forward progress (consider what a program requires to not be useless)

Takeaway: Don't introduce a data race. 😀


volatile is something else

volatile is not a tool relevant to the happens before relation. It's a tool for I/O.

  • volatile is a tool for communicating with things outside of your program.
  • atomics are a tool for communicating within your program.

Memory Orderings


CAS: Compare and Swap

Edited by Matthias Kretz