C++ 原子操作完全指南 + 单例模式实战
C 原子操作完全指南 单例模式实战一、std::atomic 基础1.1 基本用法std::atomic保证对变量的读写是不可中断的线程安全无需显式加锁。#includeatomic#includethread#includeiostreamstd::atomicintcounter{0};voidincrement(){for(inti0;i100000;i){counter;// 原子自增线程安全}}intmain(){std::threadt1(increment);std::threadt2(increment);t1.join();t2.join();std::coutcounter\n;// 保证输出 200000}1.2 核心 API操作说明load()原子读store(val)原子写exchange(val)原子交换返回旧值compare_exchange_weak(expected, desired)CAS原子比较并交换fetch_add(val)/fetch_sub(val)原子加减返回旧值/--重载运算符等价于fetch_add(1)std::atomicinta{10};intxa.load();// x 10a.store(20);// a 20intolda.exchange(30);// old 20, a 30intexpected30;booloka.compare_exchange_weak(expected,40);// 如果 a 30则 a 40返回 true// 如果 a ! 30则 expected a 的当前值返回 false二、内存序 (Memory Order)std::atomic默认使用memory_order_seq_cst顺序一致性性能开销最大。可以显式指定更宽松的内存序。2.1 五种内存序宽松程度 seq_cst acquire/release acq_rel relaxed (最强) (最弱性能最好)内存序含义适用场景memory_order_relaxed只保证原子性不保证顺序纯计数器如引用计数memory_order_acquire读操作之后的读写不会被重排到这次读之前获取锁、读取共享数据memory_order_release写操作之前的读写不会被重排到这次写之后释放锁、发布共享数据memory_order_acq_rel同时包含 acquire release读-修改-写操作如 CASmemory_order_seq_cst全局顺序一致性默认简单但最慢2.2 Acquire-Release 同步示例#includeatomic#includethreadstd::atomicintdata{0};std::atomicboolready{false};voidproducer(){data.store(42,std::memory_order_relaxed);// ① 写数据ready.store(true,std::memory_order_release);// ② 发布信号}voidconsumer(){while(!ready.load(std::memory_order_acquire))// ③ 等待信号;// ④ 保证能看到 ① 的写入std::coutdata.load(std::memory_order_relaxed)\n;// 一定输出 42}intmain(){std::threadt1(producer);std::threadt2(consumer);t1.join();t2.join();}关键release写和acquire读配对形成一个同步点。保证在release之前的所有写操作对acquire之后的读操作可见。三、自旋锁实现CAS 实战#includeatomic#includethreadclassSpinLock{std::atomic_flag flagATOMIC_FLAG_INIT;public:voidlock(){// test_and_set: 原子地设置 flag 为 true返回旧值while(flag.test_and_set(std::memory_order_acquire)){// 自旋等待}}voidunlock(){flag.clear(std::memory_order_release);}};SpinLock spinlock;intshared0;voidwork(){for(inti0;i10000;i){spinlock.lock();shared;// 临界区spinlock.unlock();}}C20 起std::atomic_flag的test()方法可以只读不修改。四、无锁队列简单示例templatetypenameTclassLockFreeStack{structNode{T data;Node*next;};std::atomicNode*head{nullptr};public:voidpush(constTvalue){Node*new_nodenewNode{value,nullptr};// CAS 循环如果 head 没变就更新为 new_nodedo{new_node-nexthead.load(std::memory_order_relaxed);}while(!head.compare_exchange_weak(new_node-next,// expectednew_node,// desiredstd::memory_order_release,std::memory_order_relaxed));}boolpop(Tresult){Node*old_headhead.load(std::memory_order_acquire);while(old_head!nullptr){if(head.compare_exchange_weak(old_head,old_head-next,std::memory_order_release,std::memory_order_relaxed)){resultold_head-data;deleteold_head;// 实际工程中需要用 Hazard Pointer 或 RCUreturntrue;}}returnfalse;}};五、注意事项坑说明不是万能锁原子操作适合简单计数/标志复杂逻辑还是要用mutexABA 问题CAS 中值从 A→B→ACAS 认为没变。解决带标签的指针Tagged Pointer伪共享 (False Sharing)两个原子变量在同一缓存行不同 CPU 核频繁修改会互相拖累。解决alignas(64)只能用于平凡可复制类型std::atomicstd::string不行std::atomicint可以compare_exchange_weak vs strongweak可能伪失败被中断适合循环strong保证真失败才返回 false适合单次检查性能对比std::atomicinta{0};// 最慢但最直观a.store(1);// 等价于 memory_order_seq_cst// 快 2~10 倍x86 上差距小ARM 上差距大a.store(1,std::memory_order_relaxed);经验法则如果不需要跨线程的happens-before关系用relaxed如果需要发布-订阅模式用release/acquire配对如果搞不清用默认的seq_cstcorrectness first六、单例模式 原子操作实战6.1 基于 atomic 的双检查锁DCLPC11 之前 DCLP 有指令重排序问题C11 引入std::atomic后可以安全实现。#includeatomic#includemutex#includeiostreamclassSingleton{public:staticSingleton*getInstance(){Singleton*tmpinstance.load(std::memory_order_acquire);if(tmpnullptr){// 第一次检查无锁std::lock_guardstd::mutexlock(mutex);// 加锁tmpinstance.load(std::memory_order_relaxed);if(tmpnullptr){// 第二次检查有锁tmpnewSingleton();// release: 保证 new Singleton() 的构造完成// 对其它线程的 acquire 可见instance.store(tmp,std::memory_order_release);}}returntmp;}voiddoSomething(){std::coutSingleton::doSomething()\n;}private:Singleton()default;~Singleton()default;Singleton(constSingleton)delete;Singletonoperator(constSingleton)delete;staticstd::atomicSingleton*instance;staticstd::mutex mutex;};std::atomicSingleton*Singleton::instance{nullptr};std::mutex Singleton::mutex;// 使用intmain(){Singleton*sSingleton::getInstance();s-doSomething();}关键点instance.load(std::memory_order_acquire)确保看到其他线程release的完整构造对象instance.store(tmp, std::memory_order_release)确保构造完成后再发布指针双重检查第一次无锁快速路径第二次有锁保证唯一性6.2 基于 atomic_flag 的无锁单例更轻量如果单例构造很快可以用atomic_flag实现一个轻量级自旋锁版本的单例。#includeatomic#includethread#includeiostream#includevectorclassSpinLockSingleton{public:staticSpinLockSingleton*getInstance(){// 快速路径已初始化直接返回SpinLockSingleton*tmpinstance.load(std::memory_order_acquire);if(tmp!nullptr){returntmp;}// 慢速路径自旋等待初始化完成while(flag.test_and_set(std::memory_order_acquire)){// 自旋中检查是否其他线程已经初始化完成tmpinstance.load(std::memory_order_relaxed);if(tmp!nullptr){flag.clear(std::memory_order_release);// 释放锁虽然没拿到returntmp;}}// 拿到锁执行初始化tmpinstance.load(std::memory_order_relaxed);if(tmpnullptr){tmpnewSpinLockSingleton();instance.store(tmp,std::memory_order_release);std::coutSingleton initialized by thread\n;}flag.clear(std::memory_order_release);returntmp;}intgetValue()const{returnvalue;}private:SpinLockSingleton():value(42){}~SpinLockSingleton()default;staticstd::atomicSpinLockSingleton*instance;staticstd::atomic_flag flag;intvalue;};std::atomicSpinLockSingleton*SpinLockSingleton::instance{nullptr};std::atomic_flag SpinLockSingleton::flagATOMIC_FLAG_INIT;// 多线程测试intmain(){std::vectorstd::threadthreads;for(inti0;i10;i){threads.emplace_back([](){auto*sSpinLockSingleton::getInstance();std::coutValue: s-getValue()\n;});}for(autot:threads)t.join();}6.3 基于 call_once 的现代写法推荐生产环境虽然这不是纯 atomic 实现但它是最安全的现代 C 单例写法底层由标准库保证原子性。#includemutex#includeatomic#includeiostreamclassModernSingleton{public:staticModernSingletongetInstance(){std::call_once(initFlag,ModernSingleton::init);return*instance;}voiddoSomething(){std::coutModernSingleton::doSomething(), valuevalue\n;}private:ModernSingleton():value(100){}~ModernSingleton()default;staticvoidinit(){instancenewModernSingleton();}staticstd::once_flag initFlag;staticModernSingleton*instance;intvalue;};std::once_flag ModernSingleton::initFlag;ModernSingleton*ModernSingleton::instancenullptr;6.4 基于 static local variable 的最简写法C11 起线程安全classSimpleSingleton{public:staticSimpleSingletongetInstance(){staticSimpleSingleton instance;// C11 起保证线程安全初始化returninstance;}voiddoSomething(){}private:SimpleSingleton()default;~SimpleSingleton()default;SimpleSingleton(constSimpleSingleton)delete;SimpleSingletonoperator(constSimpleSingleton)delete;};C11 标准规定函数内的static局部变量初始化是线程安全的由编译器插入原子操作保证。这是最推荐的写法。七、单例模式选择指南实现方式线程安全性能复杂度推荐场景static local✅ C11 标准保证最优无锁最低首选绝大多数场景std::call_once✅优低需要延迟初始化且构造可能抛异常atomic DCLP✅优中学习原子操作原理、需要手动控制内存序atomic_flag 自旋锁✅良中构造极快、不想用 mutexmutex✅一般低简单场景不追求极致性能八、一句话总结std::atomic提供无锁的原子操作通过内存序控制可见性和重排序。relaxed最快但最弱release/acquire是性能与正确性的平衡点seq_cst最安全但最慢。CAS 是实现无锁数据结构的基石要小心 ABA 和伪共享。单例模式优先用 C11 的static local变量学习原子操作原理时可以用atomic DCLP实现。声明本文档由 AIMoonshot AI / Kimi辅助生成内容仅供参考请根据实际情况核实和使用。 仅供学习使用

相关新闻

深度剖析 AI 在电商行业的落地应用、瓶颈与发展机遇

深度剖析 AI 在电商行业的落地应用、瓶颈与发展机遇

随着生成式AI与AI Agent技术快速普及,人工智能已从概念工具,升级为电商数字化转型的核心生产力。AI全面覆盖电商内容、营销、服务、供应链全链路,大幅解决传统电商高成本、低产能、粗放运营的痛点。本文结合TKONE电商AI落地实战,精…

2026/10/19 22:55:09 阅读更多 →
基于SpringBoot+Vue的家用车辆美容养护管理系统设计与实现开题报告

基于SpringBoot+Vue的家用车辆美容养护管理系统设计与实现开题报告

、课题研究背景与意义 (一)研究背景 随着国民经济水平的持续提升与汽车工业的快速发展,家用汽车普及率逐年攀升,汽车已成为大众日常出行的核心交通工具。随着家用车辆保有量的不断增长,车主对车辆定期美容、保养、维修…

2026/10/20 0:44:27 阅读更多 →
Source Han Serif CN:如何用开源方案解决中文字体商用困境?

Source Han Serif CN:如何用开源方案解决中文字体商用困境?

Source Han Serif CN:如何用开源方案解决中文字体商用困境? 【免费下载链接】source-han-serif-ttf Source Han Serif TTF 项目地址: https://gitcode.com/gh_mirrors/so/source-han-serif-ttf 在中文设计领域,商用字体授权费用动辄数…

2026/10/20 1:12:46 阅读更多 →

最新新闻

基于Simulink的龙伯格观测器无传感器转速估计建模与仿真

基于Simulink的龙伯格观测器无传感器转速估计建模与仿真

做电机驱动的,很多场合不想装编码器。装一个编码器不仅贵,振动、油污、线缆耦合、安装间隙,哪一样都是售后问题的来源。于是龙伯格观测器(Luenberger Observer)就成了替代方案里最常见的一种——它不需要额外硬件&…

2026/10/20 18:54:56 阅读更多 →
企业微信会话存档配置与拉取消息全链路实战

企业微信会话存档配置与拉取消息全链路实战

简介:这份资源面向熟悉Java开发、需要落地企业微信会话内容存档功能的技术人员,围绕服务器配置、事件接收、公钥生成与配置、依赖引入、SDK使用以及消息拉取与解密等关键环节,提供从零开始的完整实现思路。压缩包共20个文件,约31K…

2026/10/20 18:54:56 阅读更多 →
STM32F103 I2C从机中断接收实战:事件状态机与避坑指南

STM32F103 I2C从机中断接收实战:事件状态机与避坑指南

简介:STM32F103 I2C通信-中断接收数据是一份面向嵌入式开发者的标准库工程资源,专注解决STM32F103CB在I2C通信中通过中断方式高效接收数据的实现问题,适用于工业控制、医疗设备、消费电子等板级短距离通信场景。包内共227个文件,包…

2026/10/20 18:54:56 阅读更多 →
YOLO复杂场景检测提升:C3k2融合CSAM三重注意力改进实践

YOLO复杂场景检测提升:C3k2融合CSAM三重注意力改进实践

最近在调一个复杂场景检测项目,场景里全是遮挡、近色背景和低照度小目标,用YOLO系列默认的C3k2做主干部件,mAP卡在某个值上死活上不去。后来参考了WACV 2024上那篇关于跨切片建模注意力(CSAM)的思路,把C3k2…

2026/10/20 18:54:56 阅读更多 →
时域降维STAP:机载雷达mDT杂波抑制从原理到仿真

时域降维STAP:机载雷达mDT杂波抑制从原理到仿真

简介:面向雷达信号处理方向的学生、科研人员及工程开发者,资源提供时域降维空时自适应处理中多普勒单元截断算法的仿真实现。传统方法需要对全部多普勒单元联合处理,计算复杂度随数据维度急剧上升;该算法只选取目标附近的少量多普…

2026/10/20 18:54:55 阅读更多 →
多轮对话在线强化学习更新频率怎么定?OpenClaw 框架原理与调参指南

多轮对话在线强化学习更新频率怎么定?OpenClaw 框架原理与调参指南

前两天有朋友问了我一个问题:OpenClaw 这类做多轮对话策略优化的框架,在线强化学习的更新频率到底怎么定?我当时愣了几秒,因为这个问题看着像参数调优,实际问的是整套在线强化学习方案的骨架。更新频率定得太高&#x…

2026/10/20 18:53:55 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

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

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

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

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

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

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

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

2026/10/20 10:02:08 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

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

2026/10/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

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

2026/10/20 9:50:45 阅读更多 →