当前位置: 首页 > news >正文

C++内存序

在 C++ 中,内存序(Memory Order)是多线程编程中原子操作的重要概念,它用于控制原子操作的内存同步行为。C++11 引入了<atomic>头文件,提供了内存序来控制多线程环境下的内存访问顺序。

内存序的作用

内存序主要解决两个问题:

  1. 可见性:一个线程对共享数据的修改何时对其他线程可见

  2. 顺序性:操作指令的执行顺序如何被其他线程观察

六种内存序

1.memory_order_relaxed

最宽松的顺序约束,只保证原子性,不保证顺序。

cpp

std::atomic<int> x(0); x.store(1, std::memory_order_relaxed); // 不保证其他线程立即看到这个值

2.memory_order_consume

依赖于该原子操作的后续操作不会被重排序到该操作之前(依赖关系)。

cpp

std::atomic<int*> ptr; int data; // 线程1 data = 42; ptr.store(&data, std::memory_order_consume); // 线程2 int* p = ptr.load(std::memory_order_consume); if (p != nullptr) { // 保证能看到 data = 42 int val = *p; }

3.memory_order_acquire

用于读操作,保证该操作之后的所有读写不会被重排序到该操作之前。

cpp

std::atomic<bool> flag(false); int data = 0; // 线程1 data = 42; flag.store(true, std::memory_order_release); // 线程2 while (!flag.load(std::memory_order_acquire)); // 这里保证能看到 data = 42

4.memory_order_release

用于写操作,保证该操作之前的所有读写不会被重排序到该操作之后。

cpp

// 与上面 acquire 配合使用

5.memory_order_acq_rel

同时包含 acquire 和 release 语义,用于读-修改-写操作。

cpp

std::atomic<int> counter(0); counter.fetch_add(1, std::memory_order_acq_rel);

6.memory_order_seq_cst

最严格的顺序约束(默认),保证所有线程看到相同的操作顺序。

cpp

std::atomic<int> x(0); x.store(1); // 默认使用 memory_order_seq_cst

典型使用模式

1.Release-Acquire 同步

cpp

std::atomic<bool> ready(false); int data = 0; // 线程1(生产者) data = 42; ready.store(true, std::memory_order_release); // 线程2(消费者) while (!ready.load(std::memory_order_acquire)); // 这里保证能看到 data = 42

2.Release-Consume 同步

cpp

std::atomic<int*> ptr(nullptr); int value; // 线程1 value = 100; ptr.store(&value, std::memory_order_release); // 线程2 int* p = ptr.load(std::memory_order_consume); if (p != nullptr) { // 保证能看到 p 指向的数据 int v = *p; // v = 100 }

3.自旋锁实现

cpp

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); } };

性能考虑

  • relaxed:性能最好,但需要谨慎使用

  • seq_cst:性能最差,但最容易理解

  • acquire/release:在性能和正确性之间取得平衡

实用建议

  1. 优先使用默认的 seq_cst,除非有性能瓶颈

  2. 理解 happens-before 关系后再使用宽松内存序

  3. 测试多线程代码,内存序错误很难调试

  4. 使用现成的同步原语(如 mutex, condition_variable)通常更安全

示例:无锁计数器

cpp

#include <atomic> #include <thread> #include <iostream> class Counter { std::atomic<int> count{0}; public: void increment() { count.fetch_add(1, std::memory_order_relaxed); } int get() const { return count.load(std::memory_order_acquire); } }; int main() { Counter counter; std::thread t1([&]() { for (int i = 0; i < 1000000; ++i) { counter.increment(); } }); std::thread t2([&]() { for (int i = 0; i < 1000000; ++i) { counter.increment(); } }); t1.join(); t2.join(); std::cout << "Count: " << counter.get() << std::endl; return 0; }
http://www.jsqmd.com/news/212061/

相关文章:

  • linux redis简单操作
  • FPGA应用开发和仿真【3.3】
  • 要实现应用的高弹性、可扩展性与快速迭代,可以结合现代云原生技术栈,包括容器化(如Docker)、Kubernetes编排、微服务架构
  • Java进阶文件输入输出实操(图片拷贝)
  • 在软件开发中,熟练掌握一些常用工具如 Git、Docker 和 IDE 可以极大提升开发效率和协作质量
  • 爆火!7款AI写论文神器,20分钟生成2.5万字问卷类论文,真实参考文献!
  • 深度测评2026最新!9款AI论文软件评测:本科生毕业论文全场景推荐
  • 在磁盘调度中,当进程请求读写磁盘时,操作系统需依次进行移臂调度和旋转调度,以高效定位数据所在的物理位置
  • 什么是Leader AP
  • 在 Ubuntu 18.04 (WSL) 上配置 LazyVim
  • React Native本地通知与JNI
  • 12 种 RAG(检索增强生成)的新型高级架构与方法,建议收藏!
  • Linux Kernel 4.4 `printk` 源码分析与使用详解
  • 【超全解析】前端如何优雅地判断是否为移动端?从 UA 检测到现代解决方案
  • 融合DWA的青蒿素优化算法(Artemisinin Optimization Algorithm, AOA)求解无人机三维动态避障路径规划附MATLAB代码
  • 【课程设计/毕业设计】基于python-cnn机器学习的罗马数据集训练识别
  • 在Windows11下编译openjdk 21
  • 5G时代下联邦学习在AI原生应用中的新机遇
  • Java进阶整理
  • 【四旋翼控制】基于6自由度四旋翼跟踪轨迹(利用LQR整体动作设定点控制,姿态控制和PD路径跟踪控制器Matlab仿真)
  • 牙齿拥挤数据集3206张yolo
  • Java实战:Spring Boot实现WebSocket实时通信
  • Microsoft 开发的关系型数据库管理系统(RDBMS)
  • Java进阶知识-反射
  • java进阶训练营 极客,关于架构极客大学java进阶训练营
  • Gemini认证疑难解答会
  • Django 视图基础
  • Java 进阶:异常影响性能吗?
  • 【Qt改变虚拟键盘的大小】
  • 一个在使用方法上的低级错误(MySQL场景)