mcpField
M
memory-model

memory-model

github.com/mohitmishra786开发269647 次安装18 周前更新
代码仓库

关于 memory-model

memory-model 是一项面向 Agent 的 C++ 和 Rust 内存模型技能,涵盖内存序、happens-before、原子操作与栅栏,并提供无锁结构的实践模式。

主要功能

  1. 01讲解 C++ 与 Rust 内存序
  2. 02说明 happens-before 关系
  3. 03指导原子操作与栅栏
  4. 04提供无锁结构实践模式
  5. 05整理常见错误与修正

适用场景

  1. 01为原子操作选择内存序
  2. 02理解 acquire-release 与 seq_cst
  3. 03设计线程间数据发布
  4. 04实现无锁队列或自旋锁

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/mohitmishra786/low-level-dev-skills --skill memory-model

安装后在 Claude Code 中输入/memory-model确认已加载。

附带文件references/cpp-memory-ordering.md

详细介绍

内存模型

目的

指导 Agent 理解 C++ 和 Rust 内存模型:内存顺序、先行发生关系、原子操作、栅栏,以及无锁数据结构的实用模式。

触发条件

  • “什么是 C++ 内存模型?”
  • “原子操作应该使用哪种内存顺序?”
  • “获取-释放和 seq_cst 有什么区别?”
  • “如何在 C++ 中使用 std::atomic?”
  • “Rust 原子操作中的获取/释放是什么?”
  • “如何实现无锁队列?”

工作流

1. 内存顺序概述

现代 CPU 和编译器会为了提高性能而重新排序操作。内存模型规定了允许进行哪些重排序,以及如何实现同步。

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
2. 内存顺序
顺序C++Rust含义
Relaxed(宽松)memory_order_relaxedOrdering::Relaxed不保证顺序;仅保证原子性
Consume(消费)memory_order_consume(使用 Acquire)数据依赖顺序
Acquire(获取)memory_order_acquireOrdering::Acquire此加载会看到匹配的 release 之前的所有写入
Release(释放)memory_order_releaseOrdering::Release此存储之前的所有写入对 acquire 可见
AcqRel(获取-释放)memory_order_acq_relOrdering::AcqRel对 RMW 操作同时执行获取和释放
SeqCst(顺序一致)memory_order_seq_cstOrdering::SeqCst所有 seq_cst 操作之间存在全序
3. C++ std::atomic
#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)
}

获取-释放保证:如果线程 A 对 X 执行释放存储,而线程 B 执行的获取加载读到了 A 写入的值,那么 A 在释放之前的所有写入,对 B 在获取之后都可见。

4. 选择合适的内存顺序
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. 常见模式
// 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;
    }
};
6. 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
7. 栅栏

栅栏无需针对特定变量执行原子操作,即可提供顺序保证:

// 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);
8. 常见错误
错误修正方法
在发布/订阅中使用 Relaxed存储时使用 Release,加载时使用 Acquire
到处使用 SeqCst先进行性能分析;使用满足要求的最弱顺序
忘记非原子加载不是原子的所有共享可变数据都需要使用原子变量或互斥锁
在 C++ 中使用 volatile 保证线程安全volatile 不是内存顺序工具;应使用 atomic
在未使用 SeqCst 的情况下假设顺序一致性不同平台的默认一致性各不相同

有关内存顺序规则和先行发生关系的参考,请参阅 references/cpp-memory-ordering.md。

相关技能

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

评论

支持 Markdown