Memory Model

mohitmishra786/low-level-dev-skills/skills/low-level-programming/memory-model

by mohitmishra786bdc58472fa9fNo license253 starsListed Oct 9, 2026Updated Oct 9, 2026Repository updated 3 months ago

C++ and Rust memory model skill for concurrent programming. Use when understanding memory ordering, writing lock-free data structures, using std::atomic or Rust atomics, diagnosing data races, or selecting the correct memory order for atomic operations. Activates on queries about memory ordering, acquire-release, seq_cst, relaxed atomics, happens-before, memory barriers, std::atomic, or Rust atomic ordering.

AI-generated overview

Guides agents through C++ and Rust memory models, memory orderings, atomics, fences, and lock-free patterns.

What it does
This skill provides instructional guidance on the C++ and Rust memory models, covering memory orderings such as relaxed, acquire, release, acq_rel, and seq_cst, the happens-before relation, atomic operations, and fences. It includes decision guidance for choosing an ordering, code patterns for spinlocks, reference counting, and one-time initialisation, plus a table of common mistakes and fixes. It also points to a reference file on memory ordering rules and happens-before.
When to use it
Use it when explaining memory ordering, writing lock-free data structures, working with std::atomic or Rust atomics, diagnosing data races, or selecting the correct memory order for atomic operations. It is also relevant to questions about acquire-release, seq_cst, relaxed atomics, happens-before, and memory barriers.
Requirements
No scripts or special tooling are required; it is instructions only. It references a bundled markdown reference file on C++ memory ordering.

Memory Model

Purpose

Guide agents through C++ and Rust memory models: memory orderings, the happens-before relation, atomic operations, fences, and practical patterns for lock-free data structures.

Triggers

  • "What is the C++ memory model?"
  • "What memory order should I use for my atomic operation?"
  • "What is the difference between acquire-release and seq_cst?"
  • "How do I use std::atomic in C++?"
  • "What is acquire/release in Rust atomics?"
  • "How do I implement a lock-free queue?"

Workflow

1. Memory ordering overview

Modern CPUs and compilers reorder operations for performance. The memory model specifies what reorderings are allowed and how synchronisation is achieved.

text
Ordering strength (weakest to strongest):Relaxed < Release/Acquire < AcqRel < SeqCst
Stronger ordering = more synchronization = more correct, but slowerWeaker ordering  = fewer barriers = faster, but needs careful analysis

2. Memory orderings

OrderC++RustWhat it means
Relaxedmemory_order_relaxedOrdering::RelaxedNo ordering guarantee; just atomicity
Consumememory_order_consume(use Acquire)Data dependency ordering
Acquirememory_order_acquireOrdering::AcquireThis load sees all writes before the matching release
Releasememory_order_releaseOrdering::ReleaseAll writes before this store are visible to acquire
AcqRelmemory_order_acq_relOrdering::AcqRelBoth acquire and release on RMW ops
SeqCstmemory_order_seq_cstOrdering::SeqCstTotal order across all seq_cst operations

3. C++ std::atomic

cpp
#include <atomic>#include <thread>
std::atomic<int> counter{0};std::atomic<bool> ready{false};
// Producer threadvoid producer() {    data = 42;                              // (1) write data    ready.store(true, std::memory_order_release);  // (2) signal}
// Consumer threadvoid consumer() {    while (!ready.load(std::memory_order_acquire));  // (3) wait    assert(data == 42);                              // (4) guaranteed to see (1)}

Acquire-release guarantees: if thread A does a release store to X, and thread B does an acquire load that sees A's value, then all writes by A before the release are visible to B after the acquire.

4. Choosing the right ordering

text
Use case?├── Counter (just needs atomicity, order irrelevant)    → Relaxed├── Reference counting (decrement + final check)        → AcqRel (dec), Acquire (load 0 check)├── Publish data from one thread to another             → Release (store), Acquire (load)├── Mutual exclusion / mutex implementation             → AcqRel / SeqCst├── Lock-free queue multiple producers/consumers        → SeqCst (safest to start)└── Sequence number check (simple flag)                 → Release + Acquire

5. Common patterns

cpp
// Pattern 1: Spinlockclass Spinlock {    std::atomic_flag flag = ATOMIC_FLAG_INIT;public:    void lock() {        while (flag.test_and_set(std::memory_order_acquire))            ; // spin    }    void unlock() {        flag.clear(std::memory_order_release);    }};
// Pattern 2: Reference countingclass RefCounted {    std::atomic<int> refcount{1};public:    void addref() {        refcount.fetch_add(1, std::memory_order_relaxed);  // only need atomicity    }    void release() {        if (refcount.fetch_sub(1, std::memory_order_acq_rel) == 1) {            // AcqRel ensures we see all writes from other releasers            delete this;        }    }};
// Pattern 3: One-time initialisationclass LazyInit {    std::atomic<void*> ptr{nullptr};    std::mutex mtx;public:    void* get() {        void* p = ptr.load(std::memory_order_acquire);        if (p == nullptr) {            std::lock_guard lock(mtx);            p = ptr.load(std::memory_order_relaxed);            if (p == nullptr) {                p = create();                ptr.store(p, std::memory_order_release);            }        }        return p;    }};

6. Rust atomics

rust
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};use std::sync::Arc;
// Simple counterlet counter = Arc::new(AtomicUsize::new(0));
// Incrementcounter.fetch_add(1, Ordering::Relaxed);
// Readlet val = counter.load(Ordering::Relaxed);
// Publish/subscribe patternstatic READY: AtomicBool = AtomicBool::new(false);
// Publisher threadunsafe { DATA = 42; }  // Write dataREADY.store(true, Ordering::Release);  // Signal
// Subscriber threadwhile !READY.load(Ordering::Acquire) {}let d = unsafe { DATA };  // Safe: guaranteed to see publisher's write

7. Fences

Fences provide ordering without an atomic operation on a specific variable:

cpp
// C++ fence — equivalent to a global memory barrierstd::atomic_thread_fence(std::memory_order_acquire);  // Acquire fencestd::atomic_thread_fence(std::memory_order_release);  // Release fence
// Typical use: multiple atomic writes then one fencerelaxed_atomic_a.store(1, std::memory_order_relaxed);relaxed_atomic_b.store(2, std::memory_order_relaxed);std::atomic_thread_fence(std::memory_order_release);  // barrier for all abovesentinel.store(true, std::memory_order_relaxed);

8. Common mistakes

MistakeFix
Using Relaxed for publish/subscribeUse Release on store, Acquire on load
Using SeqCst everywhereProfile first; use weakest correct ordering
Forgetting that non-atomic loads are not atomicAll shared mutable data needs atomic or mutex
Using volatile for thread safety in C++volatile is not a memory ordering tool; use atomic
Assuming sequential consistency without SeqCstEach platform has different default consistency

For memory ordering rules and happens-before reference, see references/cpp-memory-ordering.md [blocked].

Related skills

  • Use skills/runtimes/sanitizers — TSan detects data races involving non-atomic accesses
  • Use skills/rust/rust-sanitizers-miri for detecting Rust memory ordering violations with Miri
  • Use skills/low-level-programming/assembly-x86 to understand generated fence instructions
  • Use skills/debuggers/gdb for debugging concurrent programs with thread inspection

Source and attribution

Source:mohitmishra786/low-level-dev-skillsinskills/low-level-programming/memory-modelat commitbdc5847

License: No license

Content belongs to its original authors. SourceWeft indexes it from a public repository.

Report or request removal

Memory Model · skills/low-level-programming/memory-model Agent Skill | SourceWeft