无锁化编程——c++内存序使用

不承担同步责任的原子变量用relaxed,只要保证计数原子就行了 ,承担同步责任的看用啥:

1.生产者消费者模型采用acquire-release

2.或者用acq_rel只是耗性能

举例:

``

void callback()

{

// 准备数据

prepared_data[thread_id] = gather_data();

// 计数:relaxed足够

int tmp = data_count.fetch_add(1,

std::memory_order_relaxed);

// 处理第4次时进行同步,这个判断把同步责任转移到了原子变量a身上

// 同步:release

if (tmp == 3)

{

a.store(true, std::memory_order_release);

}

}

void thread1()

{

// 重置:relaxed足够

a.store(false, std::memory_order_relaxed);

data_count.store(0, std::memory_order_relaxed);

//调用异步接口,把这两个原子变量扔给多线程回调处理

asyncHandle(a, data_count, callback);//伪代码,异步接口立即返回

// 等待:acquire必须(与release配对)

while (!a.load(std::memory_order_acquire))

{

sleep(5ms);

}

// 安全使用prepared_data

use(prepared_data);

}

``

可以看到用到了relaxed和acquire、release,该场景如下说明:
(1)线程1先启动 ,把各个原子变量赋初值------这个时候没有竞争,所以relaxed就足够了。然后扔给多线程回调处理(把回调函数callback注册给多线程处理,触发多线程回调),接着等待处理完成标志------这个时候涉及到多线程竞争了,线程1是消费者线程,同步责任的原子变量只有a,所以a在消费者这块用load+acquire。
(2)callback是多线程回调处理函数,其内部是处理4次数据后置完成标志位。而同步责任的原子变量只有a,所以a在生产者这块用store+release。在这个回调里呢,计数这个原子变量不涉及同步,因为加了if把同步责任转移给原子变量a了,所以呢,这个计数原子变量只要保证++是原子的就行,所以用了宽松的内存序检查relaxed。

什么叫同步责任?

在生产者消费者模型下,生产者可能多个生产者(多个线程)来准备数据,准备好数据后(判断条件和业务有关系),这些数据要被消费者感知并处理,假设准备好数据后要置标志位,那这个标志位变量就承担了同步责任。

什么叫内存序?

保证代码的执行顺序,不同的内存序编译器编译出来的代码不一样,有的可能和你写个代码的前后顺序不一样。

比如

std::atomic ready{false};

int data = 0;

// 线程1(生产者)

data = 42; // 步骤1:准备数据

ready = true; // 步骤2:设置标志

// 线程2(消费者)

while (!ready){ // 步骤3:检查标志

// 等待

}

cout << data; // 步骤4:读取数据

在没有内存序保证的情况下,步骤1和步骤2可能被重排!

什么是"重排"?编译器重排编译器为了优化,可能把代码变成:

// 编译器优化后(错误!)

ready = true; // 步骤2先执行!

data = 42; // 步骤1后执行

后果:消费者看到不一致的状态

时间线:

线程1:ready = true → data = 42 // 重排了!

线程2:看到ready=true → 读取data=0 // 读到旧数据!

6种内存序,

设计原理:

正交组合

6种内存序实际上是2个维度的组合:

维度1:操作类型(3种)
加载操作(读) :需要acquire语义
存储操作(写) :需要release语义
读-修改-写操作(RMW):需要两者兼备

维度2:同步强度(2种强度 + 1个特殊)
弱同步 :relaxed(无同步)
强同步 :seq_cst(默认,完全同步)
中间强度:consume/acquire/release/acq_rel(精确控制)

相关推荐
咩咦25 分钟前
C++学习笔记24:构造函数初始化列表
c++·学习笔记·类和对象·构造函数·初始化列表·const引用
计算机安禾39 分钟前
【c++面向对象编程】第43篇:可变参数模板(C++11):优雅处理不定长参数
java·开发语言·c++
10岁的博客1 小时前
C++ 进制转换:通用 a 进制转 b 进制(2-36进制)题解
开发语言·c++
小贾要学习2 小时前
【Linux】基于自定义TCP协议的日期计算器
linux·网络·c++·网络协议·tcp/ip
YsyaaabB2 小时前
ACM 模式通用代码模板
java·c++·python·算法
我命由我123452 小时前
C++ - 面向对象 - 析构函数
android·c语言·开发语言·c++·visualstudio·visual studio·android runtime
代码村新手3 小时前
C++-多态
开发语言·c++
玖釉-3 小时前
旋转图像:从矩阵转置、镜像到坐标变换的系统理解
c++·windows·算法·图形渲染
咩咦4 小时前
C++学习笔记23:const 成员函数
c++·学习笔记·类和对象·const·this指针·const成员函数
3DVisionary5 小时前
精密模具电极如何测形变?蓝光三维扫描3D检测方案解析
c++·数码相机·蓝光三维扫描·质量控制 qc·形位公差分析·模具电极检测·非接触三维测量