Memory Model

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

作者 mohitmishra786bdc58472fa9f无许可证253 个星标收录于 2026年10月9日更新于 2026年10月9日仓库3个月前更新

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 生成的概览

指导代理理解 C++ 与 Rust 内存模型、内存顺序、原子操作、栅栏及无锁模式。

功能
该技能提供关于 C++ 和 Rust 内存模型的指导,涵盖 relaxed、acquire、release、acq_rel、seq_cst 等内存顺序、happens-before 关系、原子操作与栅栏。它包含选择内存顺序的决策指引,自旋锁、引用计数和一次性初始化的代码模式,以及常见错误与修复对照表。它还指向一份关于内存顺序规则与 happens-before 的参考文件。
适用场景
适用于解释内存顺序、编写无锁数据结构、使用 std::atomic 或 Rust 原子类型、诊断数据竞争,或为原子操作选择正确内存顺序的场景。也适用于关于 acquire-release、seq_cst、relaxed 原子操作、happens-before 和内存屏障的问题。
运行要求
无需脚本或特殊工具,仅为说明性内容。它引用了一份随附的关于 C++ 内存顺序的 Markdown 参考文件。

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

来源与署名

来源:mohitmishra786/low-level-dev-skills位于skills/low-level-programming/memory-model提交bdc5847

许可证: 无许可证

内容归原作者所有。SourceWeft 从公开仓库中收录这些内容。

举报或申请下架