来看一下boost文档下给出的shared_ptr的多线程读写的例子
shared_ptr<int> p(new int(42));
//一个shared_ptr实体允许被多个线程读取
// thread A
shared_ptr<int> p2(p); // reads p
// thread B
shared_ptr<int> p3(p); // OK, multiple reads are safe
//一个shared_ptr实体不允许被多个线程同时读写
// thread A
p = p3; // reads p3, writes p
// thread B
p3.reset(); // writes p3; undefined, simultaneous read/write
shared_ptr引用计数是原子的,它的析构函数原子地将引用计数减去1,当多个线程对同一对象析构时,也只会出现执行顺序的交错,不会有内存泄露。
那么同理shared_ptr的构造函数、赋值、析构都是线程安全的。
何时不安全呢?就是在我们通过shared_ptr.get()和*解引用获得了指向该内存的原始指针,那么后面都是对原始指针的操作,所以我们需要自己控制线程的安全。(如shared_ptr.rest 和 swap)
通俗来讲,当我们同时读写同一个对象的时候,无法确保编译器是先操作引用计数还是先操作指针,在这个时候就需要加锁,避免出现空悬指针。
那么如何使多个线程可以对同一个shared_ptr实体进行同时读写?
运用weak_ptr这个助手检测指针是否被释放
没使用前:
class tester
{
public:
tester() {}
~tester() {}
public:
boost::shared_ptr<int> m_spData; // 可能其它类型。
};
tester gObject;
void fun(void)
{
// !!!在这大量使用sp指针.
boost::shared_ptr<int> tmp = gObject.m_spData;
}
int main()
{
// 多线程。
boost::thread t1(&fun);
boost::thread t2(&fun);
t1.join();
t2.join();
return 0;
}
改进后:
class tester
{
public:
tester() {}
~tester() {}
// 更多的函数定义…
};
void fun(boost::weak_ptr<tester> wp)
{
boost::shared_ptr<tester> sp = wp.lock;
if (sp)
{
// 在这里可以安全的使用sp指针.
}
else
{
std::cout << “指针已被释放!” << std::endl;
}
}
int main()
{
boost::shared_ptr<tester> sp1(new tester);
boost.weak_ptr<tester> wp(sp1);
// 开启两个线程,并将智能指针传入使用。
boost::thread t1(boost::bind(&fun, wp));
boost::thread t2(boost::bind(&fun, wp));
t1.join();
t2.join();
return 0;
}
使用weak_ptr.lock函数就可以得到一个shared_ptr的指针,如果该指针已经被其它地方释放,它则返回一个空的shared_ptr,也可以使用weak_ptr.expired()来判断一个指针是否被释放。