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

跟我学C++中级篇—std::shared_ptr的线程安全性分析

一、变量的线程安全性

开发者经常遇到的一个问题就是,在多线程操作资源特别是变量时,会不会导致变量的失控。只要学习过多线程开发的,往往一开始就是写同个线程来同时操作一个变量,然后打印这个变量,会发现,这个变量时而变化几次,时而不会变化,让初学者感到非常困惑。
其实在后来掌握了多线程开发后,对这种现象也就明白了。但明白了,不代表换个马甲还明白,这就是很多开发者面临的问题。比如智能指针中的std::shared_ptr是不是线程安全的?为什么?能不能阐述一下。然后,估计不少同学就卡売了。

二、std::shared_ptr的线程安全性

如果非要给一个定论,std::shared_ptr并不是线程安全的。但是为什么很多开发者经常看到或听到说“std::shared_ptr是线程安全的”这个结论呢?其实有很多是无意的情况下,把一个std::shared_ptr的个别内容给简化说明然后以讹传讹了。
std::shared_ptr可以从三个角度来看它的线程安全性:

  1. std::shared_ptr的引用计数器
    在std::shared_ptr中,引用计数器是原子操作,其当然是线程安全的。这也是为什么说“std::shared_ptr是线程安全的”一个重要的来原
  2. std::shared_ptr的赋值
    如果需要给一个std::shared_ptr指针赋值或者它们之间互相赋值,std::shared_ptr就不是线程安全的了。此时需要使用同步机制进行控制
  3. std::shared_ptr操作的对象
    如果想在多线程中操作std::shared_ptr指向的对象,如果这个对象本身没有锁或原子操作的话,同样也需要线程间的同步机制来保证线程操作的安全

通过上面的分析说明,就可以从整体了明白std::shared_ptr在线程安全方面到底哪些是安全的。而不是简单的回答是与否。

三、具体的分析

std::shared_ptr主要解决的共享指针操作相同对象时,引用数量的安全性。它重点是保护这个引用计数器是否是安全的。这才是其设计的主要目的,在C++标准中是这样描述的“The shared_ptr objects have the thread safety guarantees of a std::atomic<> for the control block, but not for the shared_ptr object itself.”。这也印证了刚刚的说明,std::shared_ptr的设计目的是为解决多线程操作同一个std::shared_ptr对象,而不能对这个线程对象改来改去。
可以把std::shared_ptr的应用分成三块即处理多线程引用的计数器、std::shared_ptr对象本身和std::shared_ptr指向的数据块。它就可以映射到上面的三个角度看问题。一定要分清楚,std::shared_ptr设计上只是满足了第一块。而对后面两部分并没有提供线程安全的机制,即不保证其线程安全性。
如果想安全的使用std::shared_ptr,最好的方法是使用C++20中的新标准std::atomic(std::shared_ptr)(在原来的实验库中有过一个atomic_shared_ptr)。但对于不少的开发者来说,可能这个标准有点高。否则的话,就只能回到传统的同步机制来保证shared_ptr的多线程环境下的安全性(在某些情况下可以借助一下std::weak_ptr,通过多写几行代码来判断)。
通过分析,就可以明白,在多线程中操作同一std::shared_ptr,要传递拷贝而非引用(引用计数器是安全的),除了这种情况下对std::shared_ptr的操作,一般都需要使用同步机制。

四、例程

下面给出一个简单的对比例程,让大家更容易问题的所在:

#include<memory>#include<thread>#include<iostream>#include<mutex>#include<vector>std::shared_ptr<int>spInit=std::make_shared<int>(100);std::mutex mtx;// 安全 :多线程直接传递,操作引用计数器voidsafeDemoUsed(){std::shared_ptr<int>local_sp=spInit;}//不安全:智能指针对象本身重新赋值需要同步机制voidunsafeDemoReUsed(){spInit=std::make_shared<int>(0);}//不安全:操作智能指针指向的对象需要同步voidunsafeDemoUsedData(){//std::lock_guard<std::mutex> lock(mtx);*spInit=0;}// 安全 :C++20使用atomic操作#include<atomic>std::atomic<std::shared_ptr<int>>asp=std::make_shared<int>(121);voidsafeDemoAtomic(){autooldSp=asp.load();autonewSp=std::make_shared<int>(111);asp.store(newSp);}intmain(){//可参考下面的代码调用其它函数即可std::vector<std::thread>threads;for(inti=0;i<3;++i){threads.emplace_back(safeDemoUsed);}for(auto&th:threads){th.join();}return0;}

请自行完善线程相关处理的并发问题,上面代码只是一个原型
注意:C++20标准的使用

五、总结

std::shared_ptr作为应用非常广泛的智能指针,用起来确实方便,但其中也隐藏着一些细节上的雷区。特别在多线程应用中,一定要搞清楚其线程安全性的范围,不能想当然的进行相关的操作。要在应用中区分对指针本身还是对资源的操作。而在对指针本身的操作中,又要分清是对引用计数器操作还是对象本身的操作。只有在明白这些区别后,才能有针对性的采用的应对的方法。与诸君共勉。

http://www.jsqmd.com/news/496677/

相关文章:

  • Matlab 模拟计算光纤 v参数 光纤模式数量 对应模式分布图 模式在纤芯能量占比 有效折射率计算
  • Qwen3-ForcedAligner-0.6B从零开始:开发者如何集成至现有语音处理流水线
  • 2026年洁净车间厂家权威推荐:技术实力与合规保障并重的TOP5精选 - 深度智识库
  • 实测才敢推 10个AI论文软件:开源免费测评,助力毕业论文与科研写作
  • ARM嵌入式学习(二) --- 入门51(中断)
  • 2026年钢模板定制厂家综合竞争力TOP5盘点与选型指南 - 2026年企业推荐榜
  • ip信息查询curl命令分享
  • Canoe-Autosar网络管理自动化测试脚本及Capl源码:全套、可直接使用修改项目配置
  • 2026年一文讲透|千笔AI,全行业通用论文神器 —— 千笔AI
  • Jsoncpp
  • 雪女-斗罗大陆-造相Z-Turbo效果对比:不同操作系统下的生成性能评测
  • 直驱风机Simulink仿真模型与永磁直驱式风力发电系统整体仿真:380V与690V双电压仿真...
  • 小白友好!ANIMATEDIFF PRO电影级渲染工作站完整使用指南
  • 手把手教你用Cursor+Coze快速搭建文生图微信小程序(附完整避坑指南)
  • Vue3响应式对象:ref与reactive对比
  • 【通信观系列】三十二、Cat.X
  • 2026权威评测:毕业论文AIGC降重盘点,免费试用首选!
  • 1.postman的基础使用方法
  • Z-Image-GGUF惊艳案例集:抽象艺术×中国传统纹样×数字人像融合创作
  • Gemma-3-270m与STM32开发实战:智能硬件项目
  • 【MCP协议实战白皮书】:20年架构师亲测——REST API吞吐量下降47%的真相与MCP生产级部署 checklist
  • MedGemma应用场景探索:医学教育、科研验证与原型开发
  • 把人当成目的,是这个时代最高级的清醒
  • 2026年激光防护罩公司权威推荐:防爆激光安全眼镜/防爆激光防护玻璃/防爆激光防护眼镜/防爆激光防护罩/选择指南 - 优质品牌商家
  • 【MCP 2.0安全规范深度解码】:20年协议安全专家逐行剖析RFC草案与OpenMCP参考实现源码
  • 开发手记(八)——ARQ异步任务队列Python快速启动
  • 成长模式——有限成长和无限成长
  • 从懵逼到通关:我的第一次 SSH 暴力破解与后门植入实验(小白视角)
  • Fish Speech 1.5语音合成:5分钟快速部署,新手也能玩转多语言TTS
  • 第5周:深入 CCM 与 DCM (断续模式)