多线程读写shared_ptrshared_ptr要加锁分析!学习笔记
(shared_ptr)的引用计数本身是安全且无锁的,但对象的读写则不是,“因为 shared_ptr 有两个数据成员,读写操作不能原子化"。使得多线程读写同一个 shared_ptr 对象需要加锁
• 一个 shared_ptr 对象实体可被多个线程同时读取;
• 两个 shared_ptr 对象实体可以被两个线程同时写入,“析构”算写操作;
• 如果要从多个线程读写同一个 shared_ptr 对象,那么需要加锁。
================================================================================
请注意,以上是 shared_ptr 对象本身的线程安全级别,不是它管理的对象的线程安全级别。
总结:书本上的一句话就是 不要对标准库抱有线程安全的幻想!!!!!!!!!需要各种分析到底安全与否!!!
shared_ptr 的数据结构:!!!!!
shared_ptr 是引用计数型(reference counting)智能指针,几乎所有的实现都采用在堆(heap)上放个计数值(count)的办法(除此之外理论上还有用循环链表的办法,不过没有实例)。具体来说,shared_ptr<Foo> 包含两个成员,一个是指向 Foo 的指针 ptr,另一个是 ref_count 指针(其类型不一定是原始指针,有可能是 class 类型,但不影响这里的讨论),指向堆上的 ref_count 对象。ref_count 对象有多个成员,具体的数据结构如图 1 所示,其中 deleter 和 allocator 是可选的。
为了简化并突出重点,后文只画出 use_count:
以上是 shared_ptr<Foo> x(new Foo); 对应的内存数据结构。
如果再执行 shared_ptr<Foo> y = x; 那么对应的数据结构如下。
但是 y=x 涉及两个成员的复制,这两步拷贝不会同时(原子)发生。
中间步骤 1,复制 ptr 指针:
中间步骤 2,复制 ref_count 指针,导致引用计数加 1:
步骤1和步骤2的先后顺序跟实现相关(因此步骤 2 里没有画出 y.ptr 的指向),我见过的都是先1后2。
既然 y=x 有两个步骤,如果没有 mutex 保护,那么在多线程里就有 race condition即资源竞争。
多线程无保护读写 shared_ptr 可能出现的 race condition:!!!!!!!!!!
考虑一个简单的场景,有 3 个 shared_ptr<Foo> 对象 x、g、n:
- shared_ptr<Foo> g(new Foo); // 线程之间共享的 shared_ptr
- shared_ptr<Foo> x; // 线程 A 的局部变量
- shared_ptr<Foo> n(new Foo); // 线程 B 的局部变量
一开始,各安其事。
线程 A 执行 x = g; (即 read g),以下完成了步骤 1,还没来及执行步骤 2。这时切换到了 B 线程。
同时编程 B 执行 g = n; (即 write G),两个步骤一起完成了。
先是步骤 1:
再是步骤 2:
这是 Foo1 对象已经销毁,x.ptr 成了空悬指针!
最后回到线程 A,完成步骤 2:
多线程无保护地读写 g,造成了“x 是空悬指针”的后果。这正是多线程读写同一个 shared_ptr 必须加锁的原因。
当然,race condition 远不止这一种,其他线程交织(interweaving)有可能会造成其他错误。
思考,假如 shared_ptr 的 operator= 实现是先复制 ref_count(步骤 2)再复制 ptr(步骤 1),会有哪些 race condition?
多线程读写shared_ptrshared_ptr要加锁分析!学习笔记的更多相关文章
- 为什么多线程读写 shared_ptr 要加锁?
https://www.cnblogs.com/Solstice/archive/2013/01/28/2879366.html 为什么多线程读写 shared_ptr 要加锁? 陈硕(giantch ...
- ELK日志分析 学习笔记
(贴一篇之前工作期间整理的elk学习笔记) ELK官网 https://www.elastic.co ELK日志分析系统 学习笔记 概念:ELK = elasticsearch + logstas ...
- 基于FP-Growth算法的关联性分析——学习笔记
数据挖掘 比之前的Ap快,因为只遍历两次. 降序 一.构建FP树 对频繁项集排序,以构成共用关系. 二.基于FP树的频繁项分析 看那个模式基出现过几次.频繁度. 看洗发液的 去掉频繁度小的 构建洗发液 ...
- 读写分离&分库分表学习笔记
读写分离 何为读写分离? 见名思意,根据读写分离的名字,我们就可以知道:读写分离主要是为了将对数据库的读写操作分散到不同的数据库节点上. 这样的话,就能够小幅提升写性能,大幅提升读性能. 我简单画了一 ...
- 在多线程中进行UI操作--ios学习笔记
iOS 上不建议在非主线程进行UI操作,在非主线程进行UI操作有很大几率会导致程序崩溃,或者出现预期之外的效果. 我开始不知道这一点,在子线程中进行了弹窗操作,结果程序就出问题了! 报的错误是(EXC ...
- java.util.BitSet 详细分析 学习笔记
1,BitSet类 大小可动态改变, 取值为true或false的位集合.用于表示一组布尔标志. 此类实现了一个按需增长的位向量.位 set 的每个组件都有一个 boolean 值.用非负的 ...
- java多线程——竞态条件与临界区 学习笔记
允许被多个线程同时执行的代码称作线程安全的代码.线程安全的代码不包含竞态条件.当多个线程同时更新共享资源时会引发竞态条件.因此,了解 Java 线程执行时共享了什么资源很重要. 一.局部变量(函数内定 ...
- C# IO流与文件读写学习笔记
本笔记摘抄自:https://www.cnblogs.com/liyangLife/p/4797583.html,记录一下学习过程以备后续查用. 一.文件系统 1.1文件系统类的介绍 文件操作类大都在 ...
- Python学习笔记进阶篇——总览
Python学习笔记——进阶篇[第八周]———进程.线程.协程篇(Socket编程进阶&多线程.多进程) Python学习笔记——进阶篇[第八周]———进程.线程.协程篇(异常处理) Pyth ...
随机推荐
- Java-马士兵设计模式学习笔记-策略模式-模拟 Comparator接口
续上一篇 <Java 模拟 Comparable接口> 一.Teacher类及Student类的比较大小方式是不固定的,比如老师除了比较职称外,还可比较工龄大小,年龄大小等.则定义Com ...
- p4213 【模板】杜教筛(Sum)
传送门 分析 我们知道 $\varphi * 1 = id$ $\mu * 1 = e$ 杜教筛即可 代码 #include<iostream> #include<cstdio> ...
- Excel课程学习
1.Excel软件简介 1.1历史上的其他数据处理软件与Microsoft Excel 1977年,苹果公司开发了一款数据处理软件,当时这款软件卖的非常好,用软件的尾巴摇动硬件的狗,当时有人因为这款软 ...
- spark sql建表的异常
在使用spark sql创建表的时候提示如下错误: missing EOF at 'from' near ')' 可以看下你的建表语句中是不是create external table .... ...
- java求几个数字的和输出详细步骤
设计思想:要求几个数字的和,就要把输入的字符串转换成浮点型,然后求和再输出. 程序流程图: 程序源代码: //此程序用于从命令行接收多个数字,就和并输出. //作者:赵东睿 //2015.9.26 p ...
- Arcgis android10.2测试版中android.view.InflateException
最近2天总是有时出现 下面这个错误 android.view.InflateException: Binary XML file line #15: Error inflating class co ...
- 具有增删改查功能的表格Demo--【BootStrap】
http://blog.csdn.net/wangmei4968/article/details/48437175
- .net core 部署在Linux系统上运行的环境搭建总结
安装Linux用的是腾讯云的centos7.5,需要安装有环境有mysql5.7 .netcore2.1 nginx1.14 1.首先是mysql的安装 我用的链接工具是putty,首先root登入 ...
- javascript 实现类似百度联想输入,自动补全功能
js 实现类似百度联想输入,自动补全功能 方案一: search是搜索框id="search" //点击页面隐藏自动补全提示框 document.onclick = functi ...
- vue 路由里面的 hash 和 history
对于 Vue 这类渐进式前端开发框架,为了构建 SPA(单页面应用),需要引入前端路由系统,这也就是 Vue-Router 存在的意义.前端路由的核心,就在于 —— 改变视图的同时不会向后端发出请求. ...