memory-model

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

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.
指导开发者掌握C++与Rust的内存模型:内存顺序、happens-before关系、原子操作、内存屏障,以及无锁数据结构的实用模式。

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?"
  • "什么是C++内存模型?"
  • "我的原子操作应该使用哪种内存顺序?"
  • "acquire-release和seq_cst有什么区别?"
  • "如何在C++中使用std::atomic?"
  • "Rust原子类型中的acquire/release是什么?"
  • "如何实现无锁队列?"

Workflow

操作流程

1. Memory ordering overview

1. 内存顺序概述

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 slower
Weaker ordering  = fewer barriers = faster, but needs careful analysis
现代CPU和编译器会对操作进行重排以提升性能。内存模型规定了哪些重排是允许的,以及如何实现同步。
text
顺序强度(从弱到强):
Relaxed < Release/Acquire < AcqRel < SeqCst

顺序越强 = 同步性越高 = 正确性更有保障,但速度越慢
顺序越弱 = 内存屏障越少 = 速度越快,但需要谨慎分析

2. Memory orderings

2. 内存顺序类型

OrderC++RustWhat it means
Relaxed
memory_order_relaxed
Ordering::Relaxed
No ordering guarantee; just atomicity
Consume
memory_order_consume
(use Acquire)Data dependency ordering
Acquire
memory_order_acquire
Ordering::Acquire
This load sees all writes before the matching release
Release
memory_order_release
Ordering::Release
All writes before this store are visible to acquire
AcqRel
memory_order_acq_rel
Ordering::AcqRel
Both acquire and release on RMW ops
SeqCst
memory_order_seq_cst
Ordering::SeqCst
Total order across all seq_cst operations
顺序类型C++Rust含义
Relaxed
memory_order_relaxed
Ordering::Relaxed
无顺序保证;仅保证原子性
Consume
memory_order_consume
(使用Acquire)数据依赖顺序
Acquire
memory_order_acquire
Ordering::Acquire
本次加载操作能看到匹配release操作之前的所有写入
Release
memory_order_release
Ordering::Release
本次存储操作之前的所有写入,对执行acquire加载的线程可见
AcqRel
memory_order_acq_rel
Ordering::AcqRel
在读写修改(RMW)操作上同时具备acquire和release特性
SeqCst
memory_order_seq_cst
Ordering::SeqCst
所有seq_cst操作遵循全局统一顺序

3. C++ std::atomic

3. C++ std::atomic

cpp
#include <atomic>
#include <thread>

std::atomic<int> counter{0};
std::atomic<bool> ready{false};

// Producer thread
void producer() {
    data = 42;                              // (1) write data
    ready.store(true, std::memory_order_release);  // (2) signal
}

// Consumer thread
void 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.
cpp
#include <atomic>
#include <thread>

std::atomic<int> counter{0};
std::atomic<bool> ready{false};

// 生产者线程
void producer() {
    data = 42;                              // (1) 写入数据
    ready.store(true, std::memory_order_release);  // (2) 发送信号
}

// 消费者线程
void consumer() {
    while (!ready.load(std::memory_order_acquire));  // (3) 等待
    assert(data == 42);                              // (4) 保证能看到(1)的写入
}
Acquire-release保证:如果线程A对X执行release存储,线程B执行acquire加载并读取到A写入的值,那么A在release之前的所有写入操作,在B执行acquire之后都对B可见。

4. Choosing the right ordering

4. 选择合适的内存顺序

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
text
使用场景?
├── 计数器(仅需原子性,顺序无关)    → Relaxed
├── 引用计数(递减+最终检查)        → AcqRel(递减)、Acquire(检查是否为0)
├── 单线程向另一线程发布数据             → Release(存储)、Acquire(加载)
├── 互斥实现 / 互斥锁实现             → AcqRel / SeqCst
├── 多生产者/消费者无锁队列        → SeqCst(入门时最安全)
└── 序列号检查(简单标志)                 → Release + Acquire

5. Common patterns

5. 常见模式

cpp
// Pattern 1: Spinlock
class 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 counting
class 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 initialisation
class 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;
    }
};
cpp
// 模式1:自旋锁
class Spinlock {
    std::atomic_flag flag = ATOMIC_FLAG_INIT;
public:
    void lock() {
        while (flag.test_and_set(std::memory_order_acquire))
            ; // 自旋
    }
    void unlock() {
        flag.clear(std::memory_order_release);
    }
};

// 模式2:引用计数
class RefCounted {
    std::atomic<int> refcount{1};
public:
    void addref() {
        refcount.fetch_add(1, std::memory_order_relaxed);  // 仅需原子性
    }
    void release() {
        if (refcount.fetch_sub(1, std::memory_order_acq_rel) == 1) {
            // AcqRel确保我们能看到其他release操作的所有写入
            delete this;
        }
    }
};

// 模式3:延迟初始化
class 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

6. Rust原子类型

rust
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::Arc;

// Simple counter
let counter = Arc::new(AtomicUsize::new(0));

// Increment
counter.fetch_add(1, Ordering::Relaxed);

// Read
let val = counter.load(Ordering::Relaxed);

// Publish/subscribe pattern
static READY: AtomicBool = AtomicBool::new(false);

// Publisher thread
unsafe { DATA = 42; }  // Write data
READY.store(true, Ordering::Release);  // Signal

// Subscriber thread
while !READY.load(Ordering::Acquire) {}
let d = unsafe { DATA };  // Safe: guaranteed to see publisher's write
rust
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::Arc;

// 简单计数器
let counter = Arc::new(AtomicUsize::new(0));

// 自增
counter.fetch_add(1, Ordering::Relaxed);

// 读取
let val = counter.load(Ordering::Relaxed);

// 发布/订阅模式
static READY: AtomicBool = AtomicBool::new(false);

// 发布者线程
unsafe { DATA = 42; }  // 写入数据
READY.store(true, Ordering::Release);  // 发送信号

// 订阅者线程
while !READY.load(Ordering::Acquire) {}
let d = unsafe { DATA };  // 安全:保证能看到发布者的写入

7. Fences

7. 内存屏障

Fences provide ordering without an atomic operation on a specific variable:
cpp
// C++ fence — equivalent to a global memory barrier
std::atomic_thread_fence(std::memory_order_acquire);  // Acquire fence
std::atomic_thread_fence(std::memory_order_release);  // Release fence

// Typical use: multiple atomic writes then one fence
relaxed_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 above
sentinel.store(true, std::memory_order_relaxed);
内存屏障无需针对特定变量的原子操作即可提供顺序保证:
cpp
// C++内存屏障 — 等效于全局内存屏障
std::atomic_thread_fence(std::memory_order_acquire);  // Acquire屏障
std::atomic_thread_fence(std::memory_order_release);  // Release屏障

// 典型用法:多次原子写入后执行一次屏障
relaxed_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);  // 对上述所有操作生效的屏障
sentinel.store(true, std::memory_order_relaxed);

8. Common mistakes

8. 常见错误

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.
错误修复方案
在发布/订阅场景中使用Relaxed顺序存储时使用Release,加载时使用Acquire
所有场景都使用SeqCst先做性能分析;使用满足需求的最弱顺序
忘记非原子加载操作不具备原子性所有共享可变数据都需要原子类型或互斥锁保护
在C++中用
volatile
保证线程安全
volatile
不是内存顺序工具;使用
atomic
未使用SeqCst却假设顺序一致性不同平台的默认一致性规则不同
关于内存顺序规则和happens-before的参考内容,请查看references/cpp-memory-ordering.md

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
  • 使用
    skills/runtimes/sanitizers
    — TSan可检测涉及非原子访问的数据竞争
  • 使用
    skills/rust/rust-sanitizers-miri
    ,通过Miri检测Rust内存顺序违规
  • 使用
    skills/low-level-programming/assembly-x86
    理解生成的屏障指令
  • 使用
    skills/debuggers/gdb
    调试并发程序,进行线程检查