C++ 无锁编程:原子操作、内存顺序与生产者-消费者模型的实战指南
2026/7/27 5:09:13 网站建设 项目流程

目录

  • 1,六大内存序
  • 2,原子操作
    • 2.1,原子操作的核心操作,基础操作:store 和 load
  • 3,利用内存模型和原子操作的生产者消费者模型设计

1,六大内存序

内存顺序类型核心特点
memory_order_relaxed宽松(无同步)只保证原子性,不保证顺序。不引入同步屏障,允许编译器和 CPU 任意重排
memory_order_consume消费(已过时)依赖当前原子变量的后续操作不被重排到它之前。(不推荐使用,编译器通常降级为 acquire)
memory_order_acquire获取(读屏障)该原子读操作之后的所有读写操作都不能重排到该操作之前。
memory_order_release释放(写屏障)该原子写操作之前的所有读写操作都不能重排到该操作之后
memory_order_acq_rel获取-释放(读写屏障)同时具备 acquire 和 release 效果,用于 Read-Modify-Write 操作(如 exchange)。
memory_order_seq_cst顺序一致性(最强)全局所有线程看到统一的修改顺序,最强最直观,但性能开销最大。


1,memory_order_release 释放----写屏障 可以理解为,原子操作的时候进行写操作,在写完释放给别的线程读之前,
必须把此线程在自身缓冲区写的数据全部同步到 公共的缓存中?
“线程在执行 Release 写操作时,必须确保本线程在 Release 之前发生的所有写操作,
都已经对其它核心可见(即排空到共享缓存),然后才允许执行 Release 这个写操作本身。”

2,memory_order_acquire 获取----读屏障 可以理解为,必须先将公共区的数据都读完之后,在进行其他的操作,比如写操作。


2,原子操作

原子操作(Atomic Operation)是指不可被中断的一个或一系列操作。在多线程环境中,原子操作要么全部执行完成,要么完全不执行,不会出现"执行到一半被其他线程干扰"的情况。

2.1,原子操作的核心操作,基础操作:store 和 load

操作函数原型允许的内存顺序
写入void store(T desired, memory_order order = seq_cst)relaxed, release, seq_cst
读取T load(memory_order order = seq_cst) constrelaxed, acquire, seq_cst
std::atomic<int>value{0};// store 操作value.store(42);// 默认 seq_cstvalue.store(100,std::memory_order_release);// 显式指定 releasevalue.store(1,std::memory_order_relaxed);// 最弱的顺序// load 操作int x=value.load();// 默认 seq_cstint y=value.load(std::memory_order_acquire);// 显式指定 acquireint z=value.load(std::memory_order_relaxed);// 最弱的顺序

store 不能使用 memory_order_acquire 或 memory_order_acq_rel

load 不能使用 memory_order_release 或 memory_order_acq_rel

操作函数原型说明
交换T exchange(T desired, memory_order order = seq_cst)用新值替换旧值,返回旧值
CAS(弱)bool compare_exchange_weak(T& expected, T desired, …)可能虚假失败,适合循环
CAS(强)bool compare_exchange_strong(T& expected, T desired, …)不会虚假失败
算术T fetch_add(T arg, memory_order order = seq_cst)加、减、与、或、异或
std::atomic<int>counter{10};// exchange:交换并返回旧值int old=counter.exchange(20);// old = 10, counter = 20// fetch_add:原子加int previous=counter.fetch_add(5);// previous = 20, counter = 25// compare_exchange:CAS(Compare-And-Swap)int expected=25;if(counter.compare_exchange_strong(expected,100)){// 如果 counter 当前是 25,替换为 100,expected 不变std::cout<<"替换成功!counter = 100"<<std::endl;}else{// 替换失败,expected 被更新为 counter 的实际值std::cout<<"替换失败,当前值为:"<<expected<<std::endl;}
特性compare_exchange_weakcompare_exchange_strong
虚假失败✅ 可能(即使相等也返回 false)❌ 不会(相等一定返回 true)
性能更快(某些平台可用 LL/SC 优化)稍慢(需要重试处理)
典型用法循环中(while + weak)单次检查
返回值bool(成功/失败)bool(成功/失败)
// ✅ weak 的正确用法:在循环中重试std::atomic<int>value{0};int expected=0;while(!value.compare_exchange_weak(expected,100,std::memory_order_acq_rel)){// 失败时 expected 被更新为实际值// 这里可以加一个最大重试次数限制}// ✅ strong 的典型用法:单次检查int expected=0;if(value.compare_exchange_strong(expected,100,std::memory_order_acq_rel)){// 成功处理}

3,利用内存模型和原子操作的生产者消费者模型设计

#include<iostream>#include<thread>#include<atomic>std::atomic<int>count{0};// 共享整形变量,初始为 0(绝对主角!)std::atomic<bool>ready{false};// 同步标志:true=有货待消费,false=已消费// ========== 生产者:count 不断加一 ==========voidproducer(){for(int i=1;i<=10;++i){// ① 直接修改 count(加一操作)// 使用 release,保证这次写入完成之前,之前的所有操作都已完成count.store(i,std::memory_order_release);// ② 通知消费者:count 已经更新,快来打印!// 必须用 release,保证 count 的写入在通知之前可见ready.store(true,std::memory_order_release);// ③ 等待消费者打印完成(等待 ready 被改回 false)while(ready.load(std::memory_order_acquire)){// 自旋等待,CPU 会忙等}}}// ========== 消费者:打印 count 的当前值 ==========voidconsumer(){for(int i=1;i<=10;++i){// ① 等待生产者通知(等待 ready 变成 true)while(!ready.load(std::memory_order_acquire)){// 自旋等待}// ② 读取 count 的最新值并打印// 用 acquire 保证读到的 count 一定是生产者 release 写进去的最新值int value=count.load(std::memory_order_acquire);std::cout<<"消费者打印: count = "<<value<<std::endl;// ③ 告诉生产者:我已经打印完了,你可以生产下一个了// 用 release 保证“打印完成”这个动作在改 ready 之前完成ready.store(false,std::memory_order_release);}}intmain(){std::threadt1(producer);std::threadt2(consumer);t1.join();t2.join();return0;}

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询