C++原子操作的内存序使用及说明(memory ordering)

 更新时间:2026年05月20日 16:29:30   作者:当归. z Z  
内存序主要用于控制多线程环境下的操作可见性和执行顺序,包括无序、消费序、获取、Release、Acq_Rels和_Seq_Cstt等等满足不同MW操作和严格顺序需求,根据不同场景选择合适的内存序,如可有助于优化性能和确保数据一致性

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

1.memory_order_relaxed(松散顺序)

特点

  • 无同步或顺序约束:仅保证原子操作的原子性,不保证操作顺序。
  • 性能最高:适合不需要同步的场景(如计数器)。

示例

std::atomic<int> counter{0};

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

适用场景

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

2.memory_order_consume(消费顺序)

特点

  • 比 acquire 更弱:仅保证依赖该原子变量的操作不被重排。
  • 用于数据依赖链(如指针解引用)。

示例

std::atomic<int*> 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<bool> 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<int> 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<int> counter{0};

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

适用场景

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

6.memory_order_seq_cst(顺序一致性)

特点

  • 最强约束:所有 seq_cst 操作按全局顺序执行(类似互斥锁)。
  • 默认选项(如果不指定内存序,原子操作默认使用 seq_cst)。
  • 性能较低,但最安全。

示例

std::atomic<bool> 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++ Cartographer源码中关于传感器的数据传递实现

    C++ Cartographer源码中关于传感器的数据传递实现

    这篇文章主要介绍了C++ Cartographer源码中关于传感器的数据传递实现,前面已经谈到了Cartographer中添加轨迹的方法和传感器的数据流动走向。发现在此调用了LaunchSubscribers这个函数来订阅相关传感器数据
    2023-03-03
  • 关于C/C++中typedef的定义与用法总结

    关于C/C++中typedef的定义与用法总结

    在C还是C++代码中,typedef都使用的很多,在C代码中尤其是多,typedef与#define有些相似,其实是不同的,特别是在一些复杂的用法上,需要的朋友可以参考下
    2012-12-12
  • C语言中指针常量和常量指针的区别

    C语言中指针常量和常量指针的区别

    本文主要介绍了C语言中指针常量和常量指针的区别,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • C++实现LeetCode(134.加油站问题)

    C++实现LeetCode(134.加油站问题)

    这篇文章主要介绍了C++实现LeetCode(134.加油站问题),本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-07-07
  • 解析ActiveMQ的使用说明总结

    解析ActiveMQ的使用说明总结

    本篇文章是对ActiveMQ的使用进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • 三种获取网页源码的方法(使用MFC/Socket实现)

    三种获取网页源码的方法(使用MFC/Socket实现)

    Windows下比较简单的获取网页源码的方法:使用MFC、使用MFC、Socket实现
    2013-12-12
  • C++输出斐波那契数列的两种实现方法

    C++输出斐波那契数列的两种实现方法

    以下是对C++中输出斐波那契数列的两种实现方法进行了详细的介绍,需要的朋友可以过来参考下,希望对大家有所帮助
    2013-10-10
  • typedef和#define用法区别总结

    typedef和#define用法区别总结

    在C还是C++代码中,typedef都使用的很多,在C代码中尤其多,typedef与#define有些相似,其实是不同的,特别是在一些复杂的用法上,下面这篇文章主要给大家介绍了关于typedef和#define用法区别总结的相关资料,需要的朋友可以参考下
    2023-06-06
  • 从零学习cmake构建系统

    从零学习cmake构建系统

    这篇文章主要为大家介绍了从零学习cmake构建系统详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-02-02
  • 深入理解C++函数栈帧

    深入理解C++函数栈帧

    本文主要介绍了C++函数栈帧,详细的介绍了C++函数栈帧的概念以及使用,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-07-07

最新评论