1. 线程安全的定义
多线程操作一个共享数据的时候,保证所有线程的行为是符合预期的则称为线程安全。
2. 智能指针的线程安全
2.1 智能指针的线程安全隐患(shared_ptr)
主要是以下几个方面:
(1) 引用计数的加减操作是否线程安全。
(2) 修改shared_ptr指向是否线程安全。
(3) shared_ptr<T>的T的并发操作的安全性,也应该被讨论。
2.2 引用计数的讨论
shared_ptr中除了有一个指针,指向所管理数据的地址。还有一个指针执行一个控制块的地址,里面存放了所管理数据的数量(常说的引用计数)、weak_ptr的数量、删除器、分配器等。
也就是说对于引用计数这一变量的存储,是在堆上的,多个shared_ptr的对象都指向同一个堆地址。在多线程环境下,管理同一个数据的shared_ptr在进行计数的增加或减少的时候是线程安全的吗?
答案是肯定的,这一操作是原子操作。
结论:共享引用计数的不同的shared_ptr被多个线程写,是线程安全的。
2.3 修改指向是否线程安全
场景一:同一个shared_ptr被多个线程写
先给出结论:此时不是线程安全的。
首先回顾一下shared_ptr指针的内部结构,包含两个重要的变量:ptr指针和引用计数指针。
对于shared_ptr的复制则分为两个步骤:
- 复制ptr指针
- 复制引用计数指针
引用例子: 陈硕:智能指针的探讨
考虑一个简单的场景,有 3 个 shared_ptr 对象 x、g、n:
shared_ptr<Foo> g(new Foo); // 线程之间共享的 shared_ptr
shared_ptr<Foo> x; // 线程 A 的局部变量
shared_ptr<Foo> n(new Foo); // 线程 B 的局部变量
结论:同一个shared_ptr被多个线程写,不是线程安全的;
场景二:同一个shared_ptr被多个线程读;
仅仅是读取,而未修改数据所以给出结论:
同一个shared_ptr被多个线程“读”是安全的;
3. 结论
通过分析,印证boost官方文档中的以下结论:
1)同一个shared_ptr被多个线程“读”是安全的;
2)同一个shared_ptr被多个线程“写”是不安全的;
3)共享引用计数的不同的shared_ptr被多个线程”写“ 是安全的;