C++ 原子操作的内存序(memory ordering)

std::memory_order 用于指定原子操作的内存顺序约束,控制多线程环境下的操作可见性和执行顺序。

1. memory_order_relaxed(松散顺序)

特点

  • 无同步或顺序约束:仅保证原子操作的原子性,不保证操作顺序。

  • 性能最高:适合不需要同步的场景(如计数器)。

示例

std::atomic counter{0};

void increment() {
    counter.fetch_add(1, std::memory_order_relaxed); // 无同步保证
}

适用场景

  • 统计计数、无竞争场景(如性能计数器)。


2. memory_order_consume(消费顺序)

特点

  • 比 acquire 更弱:仅保证依赖该原子变量的操作不被重排。

  • 用于数据依赖链(如指针解引用)。

示例

std::atomic ptr{nullptr};
int data = 0;

void producer() {
    data = 42;
    ptr.store(&data, std::memory_order_release); // 发布指针
}

void consumer() {
    int* p;
    while (!(p = ptr.load(std::memory_order_consume))) { // 消费指针
        // 等待
    }
    assert(*p == 42); // 仅保证 p 依赖的操作有序
}

适用场景

  • 适用于指针或数据依赖的场景(比 acquire 更高效)。


3. memory_order_acquire(获取顺序)

特点

  • 与 release 配对,确保后续操作不会重排到 acquire 之前。

  • 读取同步:保证看到 release 之前的修改。

示例

std::atomic ready{false};
int data = 0;

void producer() {
    data = 42;
    ready.store(true, std::memory_order_release); // 发布数据
}

void consumer() {
    while (!ready.load(std::memory_order_acquire)) { // 等待 release
        // 自旋
    }
    assert(data == 42); // 保证看到 data = 42
}

适用场景

  • 锁的获取、线程间数据同步。


4. memory_order_release(释放顺序)

特点

  • 与 acquire 配对,确保之前的操作不会重排到 release 之后。

  • 写入同步:保证修改对 acquire 线程可见。

示例

std::atomic flag{0};
int data = 0;

void producer() {
    data = 42;
    flag.store(1, std::memory_order_release); // 确保 data = 42 在 flag = 1 之前
}

void consumer() {
    while (flag.load(std::memory_order_acquire) != 1) { // 等待 release
        // 自旋
    }
    assert(data == 42); // 保证看到 data = 42
}

适用场景

  • 锁的释放、线程间数据发布。


5. memory_order_acq_rel(获取-释放顺序)

特点

  • 同时具备 acquire 和 release 语义

    • 如果是读-修改-写(RMW)操作(如 fetch_add),则:

      • 读取部分 采用 acquire 语义(防止后续操作重排到前面)。

      • 写入部分 采用 release 语义(防止前面操作重排到后面)。

  • 适用于 CAS(Compare-And-Swap)等操作

示例

std::atomic counter{0};

void increment() {
    counter.fetch_add(1, std::memory_order_acq_rel); // 读-修改-写
}

适用场景

  • 自旋锁、无锁数据结构(如队列、栈)。


6. memory_order_seq_cst(顺序一致性)

特点

  • 最强约束:所有 seq_cst 操作按全局顺序执行(类似互斥锁)。

  • 默认选项(如果不指定内存序,原子操作默认使用 seq_cst)。

  • 性能较低,但最安全。

示例

std::atomic x{false}, y{false};
int z = 0;

void write_x() {
    x.store(true, std::memory_order_seq_cst); // 全局可见顺序
}

void write_y() {
    y.store(true, std::memory_order_seq_cst); // 全局可见顺序
}

void read() {
    while (!x.load(std::memory_order_seq_cst)) {}
    if (y.load(std::memory_order_seq_cst)) {
        z++; // 保证 x 和 y 的修改顺序一致
    }
}

适用场景

  • 需要严格顺序的场景(如 Dekker 算法、Peterson 锁)。

7. 总结

内存序 作用 适用场景
relaxed 仅保证原子性,无顺序约束 计数器、无竞争统计
consume 仅保证依赖该原子变量的操作有序 指针发布(较少使用)
acquire 保证后续操作不会重排到它之前(读同步) 锁获取、数据同步
release 保证之前操作不会重排到它之后(写同步) 锁释放、数据发布
acq_rel 同时具备 acquire 和 release(用于 RMW 操作) 自旋锁、无锁数据结构
seq_cst 全局顺序一致(最强约束,性能最低) 需要严格顺序的算法

 

你可能感兴趣的:(C++,c++,算法)