C++ shared_ptr的线程安全问题

shared_ptr的线程安全问题

首先看看下面的图,这个图描述的就是对象、资源、引用计数之间的关系。
在这里插入图片描述

shared_ptr的线程安全问题需要从两个角度来分析:
(1)从引用计数的角度来看:
虽然引用计数存在于每一个shared_ptr对象中,但是实际上它是要跟随对象所管理的资源。引用计数会随着指向这块资源的shared_ptr对象的增加而增加。因此引用计数是要指向同一块资源的所有的对象共享的,所以实际上引用计数在shared_ptr底层中是以指针的形式实现的,所有的对象通过指针访问同一块空间,从而实现共享。

那么也就是说,引用计数是一个临界资源,所以在多线程中,我们必须要保证临界资源访问的安全性,因此在shared_ptr底层中在对引用计数进行访问之前,首先对其加锁,当访问完毕之后,在对其进行解锁。

所以shared_ptr的引用计数是线程安全的。

(2)从被shared_ptr对象所管理的资源来看:
shared_ptr对象所管理的资源存放在堆上,它可以由多个shared_ptr所访问,所以这也是一个临界资源。因此当多个线程访问它时,会出现线程安全的问题

首先shared_ptr对象有两个变量,一个是指向的对象的指针,还有一个就是我们上面看到的引用计数, 当shared_ptr发生拷贝的时候,是先拷贝智能指针,然后再拷贝引用计数,也就是说,shared_ptr的拷贝并不是一个原子操作。而问题就出现在这里。

用一个简单的例子来说明:

假如有下面三个同类型的shared_ptr:
shared_ptr<foo> p1;                 //线程A的局部变量
shared_ptr<foo> p2(new foo);        //线程A和线程B所共享
shared_ptr<foo> p3(new foo);        //线程B的局部变量

(1)一开始他们之间的关系可以用下图来表示:
在这里插入图片描述
(2)然后线程A先执行语句:p1=p2,在执行这条语句时,先改变ptr的指向,然后才修改引用计数。因为现在是多线程,所以很可能出现这样的情况:在线程A执行完步骤一时,还没来得及执行步骤二,就轮到线程B来执行。如下图所示:
在这里插入图片描述
(3)现在线程B开始执行p2=p3,并且没有被打断,也就是说步骤一二都完成。
先是步骤一
在这里插入图片描述
然后步骤二:
在这里插入图片描述
注意此时因为第一个资源的引用计数已经为0,所以会销毁该资源,也就是说,步骤二执行完之后,p1的ptr是一个悬空指针

(4)接下来轮到线程A执行,但是此时线程A是从上一次执行到的地方开始执行,也就是说,线程A会从步骤二开始执行。
在这里插入图片描述
所以多个shared_ptr对象对其所管理的资源的访问不是线程安全的。如果不使用锁这会造成线程安全问题。

(5)所以当我们多个线程访问同一个shared_ptr时,应该要进行加锁操作。

  • 9
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值