多线程读写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中字符串的存储
在java中,不同的字符串赋值方法,其所在的地址可能不同也就导致,两个字符串的值看似相等可是在s1==s2操作时,其结果返回的却是false 例: String s1 = "Programm ...
- Luogu 3759 [TJOI2017]不勤劳的图书管理员
再也不作死写FhqTreap作内层树了,卡的不如暴力呜呜呜…… 题意翻译:给一个序列,每个下标包含两个属性$a$和$v$,求第一个属性与下标形成的所有逆序对的第二个属性和,给出$m$个交换两个下标的操 ...
- 使用database control配置数据库时 要求在当前oracle主目录中配置监听程序
1:配置本地的环境变量 打开cmd命令界面 C:\Users\gechong>lsnrctl start 这时候报适配器错误 2.在cmd中输入 tnslsnr命令
- mysql--约束条件
主键的测试 PRIMARY KEY(PRIMARY可以省略) --查看创建表的标的定义,可以查看主键 SHOW CREATE TABLE user1; ,'king');--主键不能重复 ,'kin ...
- 【Android小技巧】android 按键如何能自动触发点击
使用button.performClick();方法 EditText 中hint的字体跟 textSize的字体大小一样大
- [译]学习Javascript的工具
本文翻译youtube上的up主kudvenkat的javascript tutorial播放单 源地址在此: https://www.youtube.com/watch?v=PMsVM7rjupU& ...
- Scrapy 中 Request 对象和 Response 对象的各参数及属性介绍
Request 对象 Request构造器方法的参数列表: Request(url [, callback=None, method='GET', headers=None, body=None,co ...
- 【转】.net算术运算导致溢出
源地址:http://blog.csdn.net/hawksoft/article/details/70470136
- UVa_Live 3664(精度坑)
题意很好理解的贪心题,然而却卡疯了的精度坑. 再次理解一下double小数运算时可能导致的精度问题,本题为避免该问题可以将小数乘以100化为整数进行比较,输出的时候再除以100就ok: 思路也很好想, ...
- Necklace of Beads POJ - 1286
\(\color{#0066ff}{ 题目描述 }\) 一个圈上有n个珠子,有三种颜色可以染,问本质不同的方案数(通过旋转和翻转重合的算一种) \(\color{#0066ff}{输入格式}\) 多组 ...