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 , is_void<_Ty2>>, int> = 0>
    _NODISCARD _Ty2& operator*() const noexcept {
        return *get();
    }

    template , int> = 0>
    _NODISCARD _Ty2* operator->() const noexcept {
        return get();
    }

    template , 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(不在乎效率了,再慢也不会比py慢吧,不崩就好)

#include 

void fun_read()
{
    std::shared_ptr sp_old;

    std::shared_ptr sp_new;

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

void fun_write()
{
    std::shared_ptr sp_old;

    std::shared_ptr sp_new;

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

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

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


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


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

仅供参考,不一定对。

你可能感兴趣的:(c++,c++,开发语言,数据结构)