weak_ptr的线程安全

文章讲述了weak_ptr作为shared_ptr的补充,用于解决循环引用导致的内存泄漏问题。在多线程环境中,weak_ptr的lock()方法是线程安全的,而expired()方法的使用需要额外的同步措施。推荐在使用weak_ptr时,通过lock()获取shared_ptr后再进行操作以确保安全性。
摘要由CSDN通过智能技术生成

shared_ptr的安全性

  1. shared_ptr的引用计数本身是线程安全(引用计数是原子操作)。
  2. 多个线程同时读同一个shared_ptr对象是线程安全的。
  3. 如果是多个线程对同一个shared_ptr对象进行读和写,则需要加锁。
  4. 多线程读写shared_ptr所指向的同一个对象,不管是相同的shared_ptr对象,还是不同的shared_ptr对象,也需要加锁保护。

weak_ptr的安全性

weak_ptr的引入作用

weak_ptr引入的作用是对shared_ptr的补充,主要解决shared_ptr里面的循环引用造成无法释放内存的问题。
eg:shared_ptr内部维护了一个共享的引用计数器,多个shared_ptr可以指向同一个资源。如果出现了循环引用的情况,引用计数永远无法归0,资源不会被释放。

weak_ptr是什么

weak_ptr 是为了配合shared_ptr而引入的,它指向一个由shared_ptr管理的资源但不影响资源的生命周期。也就是说,将一个weak_ptr绑定到一个shared_ptr不会改变shared_ptr的引用计数。
不论是否有weak_ptr指向,如果最后一个指向资源的shared_ptr被销毁,资源就会被释放。
weak_ptr更像是shared_ptr的助手而不是智能指针。

weak_ptr在多线程中的安全使用

先说结论:在多线程开发中,使用weak_ptr的expired()接口是不安全的,而lock()接口是安全的。
weak_ptr不控制对象的生命周期,但是,它知道对象是否还活着。
用lock()函数把它可以提升为shared_ptr,如果对象还活着,返回有效的shared_ptr,如果对象已经死了,提升会失败,返回一个空的shared_ptr。
提升的行为(lock())是线程安全的。

#include <iostream>
#include <memory>

class B;
class A
{
public:
std::weak_ptr<B> m_p;
int x;
};

class B
{
public:
std::weak_ptr<A> m_p;
int x;
};



int main()
{
    auto p_a = std::make_shared<A>();
    auto p_b = std::make_shared<B>();
    p_a->m_p = p_b;
    p_b->m_p = p_a;
    //使用weak_ptr解决循环引用问题


    //weak_ptr的使用

    if(!p_a->m_p.expired())         //这种使用是不安全的
    {
        p_a->m_p.lock()->x = 100;
    }

    std::shared_ptr<A> w_s_p = p_b->m_p.lock(); //这是安全的
    if(w_s_p)
    {
        w_s_p->x = 100;
    }
    else
    {
    }
    return 0;
}

查看上述代码,在第一次使用weak_ptr的时候使用了expired()接口(if(!p_a->m_p.expired()) 这行),使用完该接口后对A中的m_p进行操作。在多线程开发的过程中,可能expired()接口执行完去执行另外其他的东西了,CPU在这个时候该线程的时间片刚好用完了,去调度另一个线程了。然后当CPU返回到该线程时,可能存在p_a->m_p已经释放掉了,p_a->m_p.lock()这时候已经是一个空指针了,再去调用p_a->m_p.lock()->x显然是非法的,是不安全的。在单线程中是无所吊谓的,但是基本上像这类智能指针一般是使用在多线程的开发当中。

所以对于weak_ptr的使用,不要p_a->m_p.lock()->x这样子的使用,使用下面第二种的方式,将weak_ptr升级为shared_ptr的指针类型,然后判断当时的shared_ptr的指针状态。若指针不为空执行需要的内容,为空return…

在lock()的过程中,该接口是线程安全的。

智能指针的一些注意

  1. std::make_shared() 接口引入是在C++11中
  2. std::make_unique() 接口引入是在C++14中
  3. std::move()也是C++14中
    编译时需要注意c++版本
  4. weak_ptr的expired()可以当做use_count() == 0 使用,效率要大于use_count()
  5. shared_ptr的引用是计数是原子操作,其操作是安全的
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值