shared_ptr的线程安全
1.9 再论shared_ptr 的线程安全
虽然我们借shared_ptr 来实现线程安全的对象释放,但是shared_ptr 本身不是100% 线程安全的。它的引用计数本身是安全且无锁的,但对象的读写则不是,因为shared_ptr 有两个数据成员,读写操作不能原子化。根据文档11,shared_ptr 的线程安全级别和内建类型、标准库容器、std::string 一样,即:
一个shared_ptr 对象实体可被多个线程同时读取;
两个shared_ptr 对象实体可以被两个线程同时写入,“析构”算写操作;
如果要从多个线程读写同一个shared_ptr 对象,那么需要加锁。
请注意,以上是shared_ptr 对象本身的线程安全级别,不是它管理的对象的线程安全级别。
要在多个线程中同时访问同一个shared_ptr,正确的做法是用mutex 保护:
- MutexLock mutex; // No need for ReaderWriterLock
- shared_ptr<Foo> globalPtr;
- // 我们的任务是把globalPtr 安全地传给doit()
- void doit(const shared_ptr<Foo>& pFoo);
globalPtr 能被多个线程看到,那么它的读写需要加锁。注意我们不必用读写锁,而只用最简单的互斥锁,这是为了性能考虑。因为临界区非常小,用互斥锁也不会阻塞并发读。
为了拷贝globalPtr,需要在读取它的时候加锁,即:
- void read()
- {
- shared_ptr<Foo> localPtr;
- {
- MutexLockGuard lock(mutex);
- localPtr = globalPtr; // read globalPtr
- }
- // use localPtr since here,读写localPtr 也无须加锁
- doit(localPtr);
- }
写入的时候也要加锁:
- void write()
- {
- shared_ptr<Foo> newPtr(new Foo); // 注意,对象的创建在临界区之外
- {
- MutexLockGuard lock(mutex);
- globalPtr = newPtr; // write to globalPtr
- }
- // use newPtr since here,读写newPtr 无须加锁
- doit(newPtr);
- }
注意到上面的read() 和write() 在临界区之外都没有再访问globalPtr,而是用了一个指向同一Foo 对象的栈上shared_ptr local copy。下面会谈到,只要有这样的local copy 存在,shared_ptr 作为函数参数传递时不必复制,用reference to const 作为参数类型即可。另外注意到上面的new Foo 是在临界区之外执行的,这种写法通常比在临界区内写globalPtr.reset(new Foo) 要好,因为缩短了临界区长度。如果要销毁对象,我们固然可以在临界区内执行globalPtr.reset(),但是这样往往会让对象析构发生在临界区以内,增加了临界区的长度。一种改进办法是像上面一样定义一个localPtr,用它在临界区内与globalPtr 交换(swap()),这样能保证把对象的销毁推迟到临界区之外。练习:在write() 函数中,globalPtr = newPtr; 这一句有可能会在临界区内销毁原来globalPtr 指向的Foo 对象,设法将销毁行为移出临界区。
shared_ptr的线程安全的更多相关文章
- shared_ptr的线程安全性
一: All member functions (including copy constructor and copy assignment) can be called by multiple t ...
- shared_ptr智能指针源码剖析
(shared_ptr)的引用计数本身是安全且无锁的,但对象的读写则不是,因为 shared_ptr 有两个数据成员,读写操作不能原子化.根据文档 (http://www.boost.org/doc/ ...
- 为什么多线程读写 shared_ptr 要加锁?
https://www.cnblogs.com/Solstice/archive/2013/01/28/2879366.html 为什么多线程读写 shared_ptr 要加锁? 陈硕(giantch ...
- C++之shared_ptr总结
转自 http://blog.csdn.net/u013696062/article/details/39665247 Share_ptr也是一种智能指针.类比于auto_ptr学习.所以推荐先学习a ...
- shared_ptr 和auto_ptr智能指针
shared_ptr:计数的智能指针 它是一个包装了new操作符在堆上分配的动态对象,但它实现的是引用计数型的智能指针 ,可以被自由地拷贝和赋值,在任意的地方共享它,当没有代码使用(引用计数为0)它时 ...
- shared_ptr 用法
引入 shared_ptr 是c++为了提高安全性而添加的智能指针,方便了内存管理. 特点 shared_ptr 是通过指针保持对象共享所有权的智能指针.多个 shared_ptr 对象可占有同一对象 ...
- 深入理解智能指针之shared_ptr(一)
本文基于C++标准库源码分析shared_ptr,旨在搞清楚shared_ptr是什么,线程安全性等,目标能够安全的使用智能指针. (一)shared_ptr是一个类. 首先可以确定的是shared_ ...
- C++11智能指针
今晚跟同学谈了一下智能指针,突然想要看一下C++11的智能指针的实现,因此下了这篇博文. 以下代码出自于VS2012 <memory> template<class _Ty> ...
- Boost使用笔记(Smart_ptr)
我是Word写的,复制过来实在懒得在排版了,有兴趣的朋友可以去我的百度文库看,谢谢 http://wenku.baidu.com/view/34e485e2f61fb7360b4c653e.html ...
随机推荐
- 【BZOJ】1625: [Usaco2007 Dec]宝石手镯(01背包)
http://www.lydsy.com/JudgeOnline/problem.php?id=1625 太水了. #include <cstdio> #include <cstri ...
- Pokémon Go呼应设计:让全世界玩家疯狂沉迷
引言:什么样的呼应设计会让移动游戏玩家沉迷?那必须为玩家构建一个属于玩家本人或者被玩家认可的虚拟环境.或者说是被玩家认可的虚拟世界.在移动游戏时代.想要做到这一点并不easy.但Pokémon Go却 ...
- Erlang语言学习入门
这是一个命令行程序,可以直接在里面输入表达式进行计算,例如来一个简单的: Erlang R15B01 (erts-5.9.1) [smp:4:4] [async-threads:0] Eshell V ...
- 打开cmd闪退
我们在使用电脑过程中一般会很少用到cmd命令,CMD命令窗口在一些特殊情况时我们会用到,如PING下看网络通不通.在CMD窗口里运行命令如磁盘格式转换,但是有些朋友遇到了这样的问题,在开始运行输入CM ...
- 安装顺序----------SQL server 2008 r2;VS2008;VS2010;
[1]一般先安装了VS2008 再安装SQL server 2008 r2会报错:安装sql server 2008 报错“检查 Microsoft Visual Studio 2008 的早期版本” ...
- MySQL中关于SQL注入的相关需要的基础知识
零.绪论: 文章部分整理来源于公司同事,特此鸣谢!!! 一.关于注入点在KEY上的注入: 我们来看一个查询,你的第一个字段是过滤器(filter)第二个字段是查询的关键字,例如查询ip == 1.2. ...
- 【BZOJ3442】学习小组 费用流
[BZOJ3442]学习小组 Description [背景] 坑校准备鼓励学生参加学习小组. [描述] 共有n个学生,m个学习小组,每个学生有一定的喜好,只愿意参加其中的一些学习小组,但是校领导为学 ...
- Chrome浏览器断点调试无效的问题
问题是这样的,在使用chrome浏览器调试JavaScript的时候,突然设置的断点失效了,怎么弄都没有效果. 折腾了半天,尝试了各种方法就是没有用. 解决:重启一下chrome浏览器就好了,这似乎是 ...
- Javascript-可定义位数的十进制转二进制
// 十进制转二进制 function binary (num, Bits) { var d = parseInt(num / 2) var resArry = [num % 2] for(; d ! ...
- Oracle之rman常用命令及维护(51CTO风哥rman课程)
list 查看数据库备份的信息 查询数据库对应物 list incarnation; list backup summary; 列出当前备份信息及汇总 B是备份 F是全备 A是归档 第三个A是是否有效 ...