C/C++——atomic小记

发布时间:2026/10/27 16:38:11

C/C++——atomic小记 CAS操作CAS操作就是“compare_and_swap”比较和交换。这是实现atomic原子操作的基石在一些平台下CAS本身就是一个原子指令因此是原子的在另一些平台下CAS是硬件模拟原子的不止由一个指令组成。CAS的weak和strongCAS在C中有两种接口compare_exchange_weak 和 compare_exchange_strong 一般我们说weak是不安全但是高效的、strong是安全但是不效的。只有在多指令CAS下才有weak和strong这个说法如果是单指令CAS不会有这种区别。在多指令CAS中操作分为三步第一步LL (Load-Linked) - 读取值并标记这个内存地址 LL R1, [内存地址] ; R1 100开始监视这个地址 第二步比较 CMP R1, 期望值 ; 100 100是的 第三步SC (Store-Conditional) - 条件存储 SC R2, [内存地址] ; 尝试写入新值 ; 但如果这个地址被打扰过写入失败 ; 返回 0失败看懂了吗也就是说在第一步而第三步中间可能有其他线程会直接修改变量值因为缓存一致性对于本线程来说这个变量的寄存器值失效了所以无法写入所以执行失败。这种判断相等之后依旧执行失败的现象叫做“伪失败”正常失败是在第一步的时候比较失败这是正常的但是伪失败是在我们已经赋予CAS原子性语义的情况下中间操作失败这是逻辑上的错误所以说如果我们直接使用compare_exchange_weak可能会出现伪失败最终导致数据不一致的情况。但是这是可以避免的// weak 版本 - 可能伪失败 while (!value.compare_exchange_weak(expected, newvalue)) { // 如果失败包括伪失败expected 会被更新为当前值 // 循环重试 }而compare_exchange_strong做了什么呢// strong 的内部实现伪代码 bool compare_exchange_strong(expected, desired) { // 内部循环调用 weak 版本 while (true) { bool success compare_exchange_weak(expected, desired); if (success) { return true; // 成功了 } // 失败有两种情况 if (expected ! actual_value) { return false; // 真失败值确实变了 } // 伪失败值没变继续循环重试 // expected 已经被更新为当前值还是原值 // 继续下一次尝试 } }实际上strong也是循环重试而compare_exchange_strong和compare_exchange_weak的性能差异就体现在多出来的两个条件判断上。strong为了维护CAS原子性的语义不能把两种失败都直接返回false因此在其内部做了判断区分。atomic无锁头插链表typedef struct node { node(int val,node* ne) { _val val; _next ne; } struct node* _next; int _val 0; }Node; atomicNode* head(nullptr); void func(int i) { Node* old head.load(); Node* newnode new Node(i,nullptr); do { newnode-_next old; } while (!head.compare_exchange_weak(old, newnode)); } int main() { int k 0; vectorthread arr; for (int i 0;i10;i) { arr.push_back(thread(func, k)); } for ( auto e:arr) { e.join(); } Node* cur head.load(); while(cur!nullptr) { cout cur-_val ; cur cur-_next; } cout endl; }atomic内存序一些时候为了优化程序效率会把指令顺序重排。对于指令乱序这块需要注意的是编译器只需要保证在单线程环境下执行的结果最终一致就可以了所以指令乱序在单线程环境下完全是允许的。但是编译器并不知道哪些数据是在线程间共享而且是有可能会被修改的这些是需要开发人员去保证的。而atomic这个类天生就是为多线程而生因此一旦你使用atomic那么就需要考虑内存序问题内存序就是限制本来可以重排的命令之间的顺序以保证多线程并发安全锁在内部其实也保证了内存序只是它封装起来了我们看不到atomic的操作比如说load比如说compare_exchange_weak都可以设置内存序以防止出错。1.memory_order_relaxed最宽松语义仅保证原子操作的原子性不提供任何同步或顺序约束重排限制无编译器和CPU可任意重排该操作周围的指令示例std::atomicint x(0); x.store(42, std::memory_order_relaxed); // 仅保证原⼦性2.memory_order_acquire获取语义语义这个内存序只可以在包含读操作的atomic操作中使用比如load比如exchange读操作之后可能本线程就要能执行了这个内存序保证读操作之后的所有读写操作都一定是在可以执行之后才执行的不能因为重排而打乱导致并发问题。重排限制防止后续操作读或写被提到该操作之前执行3.memory_order_release释放语义语义这个内存序只可以在包含写操作的atomic操作中使用比如storeexchange写操作之后其他线程就会被唤醒这个内存序保证写操作之前的所有读写操作都一定是被执行的防止被唤醒的线程访问出错。重排限制防止先前操作读或写被延迟到该操作之后执行示例​​​std::atomicbool flag(false); int data 0 // 线程 1 data 42; flag.store(true, std::memory_order_release); // 保证 data 42 在 flagtrue 之前可⻅ // 线程 2 while (!flag.load(std::memory_order_acquire)) {} std::cout data; // 保证看到 data 42上面是一个线程修改另一个线程负责打印的例子如果没有 std::memory_order_release 那么有可能flag的设置会在data赋值之前这样可能会造成线程2打印出0的错误结果。如果没有 std::memory_order_acquire 编译器可能会认为while循环和打印交换没什么影响因为在线程2的函数中data没有被修改因此出现错误。4.memory_order_acq_rel获取-释放混合语义同时具有acquire和release的语义一般用于同时进行读写操作的原子操作比如fetch_add。重排限制既防止前面的操作被移到之后也防止后面的操作被移到之前双向限制示例std::atomicint counter(0); int old counter.fetch_add(1, std::memory_order_acq_rel); // 既保证之前操作不会被重排到后面也保证之后操作不会被重排到前面5.memory_order_seq_cst顺序一致性默认语义所有线程看到的内存操作顺序完全一致全局顺序一致性重排限制最强限制完全禁止所有相关重排并提供全局同步点示例std::atomicint x(0); x.store(42, std::memory_order_seq_cst); // 默认模式 int value x.load(std::memory_order_seq_cst); // 所有线程保证看到相同顺序
延伸阅读

更多相关文章

2026/10/27 16:37:45

咨询系统有风险查询功能吗?能查合作方失信信息吗

合作方踩雷的代价,比想象中大咨询公司的业务离不开合作方:审核机构、供应商、渠道商,个个都要打交道。可合作方靠不靠谱,以前只能靠打听、靠感觉,等合作到一半出了问题,项目停摆、钱收不回来,损…

2026/10/23 11:35:15

手机控制嵌入式程序烧录:移动化方案与工程实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/23 18:21:52

嵌入式蒸烤微一体机选购安装全攻略:60L双风炉详解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/27 16:33:34

40G/50G高速网络实战指南:从PAM4、PCIe到RoCEv2全栈调优

1. 这不是“换个网卡”那么简单:40G/50G接口背后的真实战场 你可能在服务器选型单上见过“支持40G/50G SFP”的标注,也可能在机房巡检时瞥见交换机面板上密密麻麻的QSFP28光模块插槽——但绝大多数人对它的理解,还停留在“比万兆快四倍”的粗…

2026/10/27 16:33:34

SpringBoot智能医院信息管理系统设计与实践

1. 项目背景与核心需求医院信息管理系统(HIS)作为医疗行业数字化转型的核心载体,正在经历从传统C/S架构向B/S云化平台的转型。这个基于SpringBoot的智能医院信息管理平台,本质上是要解决医疗业务中三个层级的痛点:业务…

2026/10/27 16:33:34

EDC临床试验管理系统:Spring Boot+Vue表单引擎与数据核查

简介:这份临床研究数据采集管理(EDC)系统源代码面向临床信息化开发者、数据管理人员及希望了解试验数据流程的学习者,覆盖试验项目管理、实验设计、CRF表单设计、疑问管理、数据录入、逻辑自动校验、CRF与DCF表单导出PDF及统计报表…

2026/10/27 16:33:34

Spring Boot+Vue临床试验EDC系统:CRF建库、逻辑核查与稽查轨迹

简介:一份面向临床研究数据管理场景的EDC系统完整源代码包,适合希望深入理解临床试验数据采集流程的开发者、研究者及计算机相关专业学习者,用于搭建可定制化的数据采集管理平台,解决试验数据标准化录入、质量核查与报表输出等问题…

2026/10/27 16:33:34

营销技能实战指南:从概念到落地的关键路径

我无法根据当前输入生成符合要求的博文。原因如下:项目标题 "marketingskills" 过于宽泛且无实质指向:它只是一个通用英文词组,未体现具体领域(如数字营销、B2B营销、短视频营销)、具体动作(如“…

2026/10/27 16:28:32

Spring Boot网上购物商城后端源码解析:从分层结构到下单链路实战

简介:本资源为基于Spring Boot框架的网上购物商城后端系统源码,面向具备Java与Spring Boot基础的开发者及计算机专业学生,可用于小型电商项目的学习参考或二次开发。系统涵盖地址管理、购物车管理、客服管理及商品评论管理四大模块&#xff0…

2026/10/27 14:24:03

全国计算机二级C语言真题PDF高效刷题指南

简介:这份PDF是全国计算机二级C语言考试的试题与答案解析,专为备考二级C语言的考生准备。内容涵盖C语言特点与设计理念、程序基本组成单位、main函数执行流程、函数嵌套调用规则、标识符命名规范、整型实型字符型数据类型、八进制十六进制数合法形式、运…

2026/10/27 9:34:54

requests+BeautifulSoup:爬虫抓取h1标题的入门实战指南

简介:一份以实战为导向的Python爬虫入门资源,面向具备基本编程基础、希望快速掌握网络数据抓取的初学者,可解决从零编写简单爬虫的常见困惑。实例以requests库发送HTTP请求、BeautifulSoup解析HTML文档,完整演示从网页中提取 标题…

2026/10/27 0:59:21

递推最小二乘参数辨识MATLAB编程:二阶系统与渐消记忆实现

简介:这是一篇面向控制系统、信号处理与机器学习等领域学习者的最小二乘参数辨识程序说明文档。资源共包含一个docx格式文档,压缩包大小七十八KB,内容围绕递推最小二乘算法和渐消记忆最小二乘算法展开:先构造一个极点位于单位圆内…

2026/10/27 0:02:28

WorkBuddy_新建任务与工作模式19_“模式选错”的典型代价

“模式选错”的典型代价 摘要 在软件工程中,设计模式、架构模式、并发模式乃至团队协作模式的选择,往往在项目早期就决定了后续的开发效率和维护成本。本文通过多个真实场景,剖析“模式选错”带来的典型代价——包括返工成本、技术债务累积、…

2026/10/27 0:02:28

WorkBuddy_新建任务与工作模式20_新手推荐路径

新手推荐路径 摘要 在 AI 辅助开发工具快速普及的今天,新手面对最多的困惑往往不是"工具够不够强",而是"我该从哪一步开始用"。本文提出一条经过实践验证的三阶段学习路径:先从 Ask(问答式交互)起…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑