c++11下,std::shared_ptr线程安全的探究

c++ 11 的shared_ptr多线程安全? - 知乎

std::shared_ptr - cppreference.com

为什么多线程读写 shared_ptr 要加锁? - 陈硕的Blog - C++博客

c++ - std::enable_shared_from_this:是否允许在析构函数中调用 shared_from_this()? - IT工具网

智能指针的线程安全 - 简书

项目因为业务升级,从单实例的大量异步,变为N实例的大量异步,用单一裸指针去管理已不合适。

于是不得不用到std::shared_ptr、std::enable_shared_from_this,刚开始没问题,某一天,突然崩了,debug下给出的也是一些无法看出问题的报错(能力有限)。

为解决bug,查阅了大量关于shared_ptr线程安全的资料,得知:

https://en.cppreference.com/w/cpp/memory/shared_ptr#Implementation_notes
依据:CPP官网

All member functions (including copy constructor and copy assignment) can be called by multiple threads on different instances of shared_ptr without additional synchronization even if these instances are copies and share ownership of the same object. If multiple threads of execution access the same instance of shared_ptr without synchronization and any of those accesses uses a non-const member function of shared_ptr then a data race will occur; the shared_ptr overloads of atomic functions can be used to prevent the data race.

词霸机翻:
所有成员函数(包括拷贝构造函数和拷贝分配)都可以在不同的shared_ptr实例上被多个线程调用,而不需要额外的同步,即使这些实例是副本并共享同一对象的所有权。如果多个执行线程在没有同步的情况下访问相同的shared_ptr实例,并且其中任何一个访问使用了shared_ptr的非常量成员函数,那么将会发生数据竞争;原子函数的shared_ptr过载可以用来防止数据竞争。

类shared_ptr下,所有const函数,都不是线程安全的。

并提到,如果要安全,那就用原子函数atomic_xxxx(C++11起可用,C++20中移除并用atomic类来实现)

看了std::shared_ptr的类实现,只有以下这些是const成员函数(线程安全)


    constexpr shared_ptr() noexcept = default;

    constexpr shared_ptr(nullptr_t) noexcept {} // construct empty shared_ptr


    template <class _Ty2 = _Ty, enable_if_t<!disjunction_v<is_array<_Ty2>, is_void<_Ty2>>, int> = 0>
    _NODISCARD _Ty2& operator*() const noexcept {
        return *get();
    }

    template <class _Ty2 = _Ty, enable_if_t<!is_array_v<_Ty2>, int> = 0>
    _NODISCARD _Ty2* operator->() const noexcept {
        return get();
    }

    template <class _Ty2 = _Ty, class _Elem = element_type, enable_if_t<is_array_v<_Ty2>, int> = 0>
    _NODISCARD _Elem& operator[](ptrdiff_t _Idx) const noexcept /* strengthened */ {
        return get()[_Idx];
    }


#if _HAS_DEPRECATED_SHARED_PTR_UNIQUE
    _CXX17_DEPRECATE_SHARED_PTR_UNIQUE _NODISCARD bool unique() const noexcept {
        // return true if no other shared_ptr object owns this resource
        return this->use_count() == 1;
    }
#endif // _HAS_DEPRECATED_SHARED_PTR_UNIQUE

    explicit operator bool() const noexcept {
        return get() != nullptr;
    }

于是,开始搞atomic

#include <atomic>

void fun_read()
{
    std::shared_ptr<myclass> sp_old;

    std::shared_ptr<myclass> sp_new;

    //读取
    std::shared_ptr<myclass> sp_new = std::atomic_load(&sp_old);
}

void fun_write()
{
    std::shared_ptr<myclass> sp_old;

    std::shared_ptr<myclass> sp_new;

    //写入
    std::atomic_store(&sp_old, sp_new);
}

我的场景是,要把shared_ptr作为函数入参,开异步线程。

std::shared_ptr<A> sp;//各线程共用的


//原先,这么写
boost::scoped_thread<boost::detach> ot(myclass::myfun,
			sp,
			shared_from_this()
		);


//现在,这么写
boost::scoped_thread<boost::detach> ot(myclass::myfun,
			std::atomic_load(&sp),
			shared_from_this()
		);

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FBI_willeach

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值