GCC STL源码解析 —— shared_ptr & weak_ptr

本文深入剖析了GCC标准库中shared_ptr和weak_ptr的源码,详细讲解了它们的构造、引用计数、访问及转换等关键功能。通过分析,揭示了在不同指针类型间复制时为何需要加锁以及加锁函数的设计原理。此外,还探讨了shared_ptr和weak_ptr在多线程环境中的竞争检测和同步策略。
摘要由CSDN通过智能技术生成

shared ptr & weak ptr

1 主要代码

1.1 count

_Mutex_base
using __gnu_cxx::__default_lock_policy;
using __gnu_cxx::_Lock_policy;
using __gnu_cxx::_S_atomic;
using __gnu_cxx::_S_mutex;
using __gnu_cxx::_S_single;

// Empty helper class except when the template argument is _S_mutex.
template <_Lock_policy _Lp>
class _Mutex_base {
   
protected:
    // The atomic policy uses fully-fenced builtins, single doesn't care.
    enum {
    _S_need_barriers = 0 };
};

template <>
class _Mutex_base<_S_mutex> : public __gnu_cxx::__mutex {
   
protected:
    // This policy is used when atomic builtins are not available.
    // The replacement atomic operations might not have the necessary
    // memory barriers.
    enum {
    _S_need_barriers = 1 };
};

_Lock_policy相关参见备注2.3.

_Sp_counted_base
template <_Lock_policy _Lp = __default_lock_policy>
class _Sp_counted_base : public _Mutex_base<_Lp> {
   
public:
    _Sp_counted_base() noexcept : _M_use_count(1), _M_weak_count(1) {
   }

    virtual ~_Sp_counted_base() noexcept {
   }

    // Called when _M_use_count drops to zero, to release the resources
    // managed by *this.
    virtual void _M_dispose() noexcept = 0;

    // Called when _M_weak_count drops to zero.
    virtual void _M_destroy() noexcept {
    delete this; }

    virtual void* _M_get_deleter(const std::type_info&) noexcept = 0;

    void _M_add_ref_copy() {
    __gnu_cxx::__atomic_add_dispatch(&_M_use_count, 1); }

    void _M_add_ref_lock() {
   
        if (!_M_add_ref_lock_nothrow()) __throw_bad_weak_ptr();
    }

    bool _M_add_ref_lock_nothrow() noexcept;

    void _M_release() noexcept {
   
        // Be race-detector-friendly.  For more info see bits/c++config.
        _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_use_count);
        if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, -1) == 1) {
   
            _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_use_count);
            _M_dispose();
            // There must be a memory barrier between dispose() and destroy()
            // to ensure that the effects of dispose() are observed in the
            // thread that runs destroy().
            // See http://gcc.gnu.org/ml/libstdc++/2005-11/msg00136.html
            if (_Mutex_base<_Lp>::_S_need_barriers) {
   
                __atomic_thread_fence(__ATOMIC_ACQ_REL);
            }

            // Be race-detector-friendly.  For more info see bits/c++config.
            _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_weak_count);
            if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count, -1) == 1) {
   
                _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_weak_count);
                _M_destroy();
            }
        }
    }

    void _M_weak_add_ref() noexcept {
    __gnu_cxx::__atomic_add_dispatch(&_M_weak_count, 1); }

    void _M_weak_release() noexcept {
   
        // Be race-detector-friendly. For more info see bits/c++config.
        _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_weak_count);
        if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count, -1) == 1) {
   
            _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_weak_count);
            if (_Mutex_base<_Lp>::_S_need_barriers) {
   
                // See _M_release(),
                // destroy() must observe results of dispose()
                __atomic_thread_fence(__ATOMIC_ACQ_REL);
            }
            _M_destroy();
        }
    }

    long _M_get_use_count() const noexcept {
   
        // No memory barrier is used here so there is no synchronization
        // with other threads.
        return __atomic_load_n(&_M_use_count, __ATOMIC_RELAXED);
    }

private:
    _Sp_counted_base(_Sp_counted_base const&) = delete;
    _Sp_counted_base& operator=(_Sp_counted_base const&) = delete;

    _Atomic_word _M_use_count;   // #shared
    _Atomic_word _M_weak_count;  // #weak + (#shared != 0)
};

template <>
inline bool _Sp_counted_base<_S_single>::_M_add_ref_lock_nothrow() noexcept {
   
    if (_M_use_count == 0) return false;
    ++_M_use_count;
    return true;
}

template <>
inline bool _Sp_counted_base<_S_mutex>::_M_add_ref_lock_nothrow() noexcept {
   
    __gnu_cxx::__scoped_lock sentry(*this);
    if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, 1) == 0) {
   
        _M_use_count = 0;
        return false;
    }
    return true;
}

template <>
inline bool _Sp_counted_base<_S_atomic>::_M_add_ref_lock_nothrow() noexcept {
   
    // Perform lock-free add-if-not-zero operation.
    _Atomic_word __count = _M_get_use_count();
    do {
   
        if (__count == 0) return false;
        // Replace the current counter value with the old value + 1, as
        // long as it's not changed meanwhile.
    } while (!__atomic_compare_exchange_n(&_M_use_count, &__count, __count + 1, true, __ATOMIC_ACQ_REL,
                                          __ATOMIC_RELAXED));
    return true;
}

template <>
inline void _Sp_counted_base<_S_single>::_M_add_ref_copy() {
   
    ++_M_use_count;
}

template <>
inline void _Sp_counted_base<_S_single>::_M_release() noexcept {
   
    if (--_M_use_count == 0) {
   
        _M_dispose();
        if (--_M_weak_count == 0) _M_destroy();
    }
}

template <>
inline void _Sp_counted_base<_S_single>::_M_weak_add_ref() noexcept {
   
    ++_M_weak_count;
}

template <>
inline void _Sp_counted_base<_S_single>::_M_weak_release() noexcept {
   
    if (--_M_weak_count == 0) _M_destroy();
}

template <>
inline long _Sp_counted_base<_S_single>::_M_get_use_count() const noexcept {
   
    return _M_use_count;
}
  • __exchange_and_add_dispatch函数参见备注2.2.
  • 构造函数将两个成员变量_M_use_count_M_weak_count初始化为1.这里的逻辑是,当它创建的时候,自己本身就是一个引用计数。
  • _M_dispose函数是纯虚函数,当_M_use_count为0时,释放this持有的资源。
  • _M_destroy函数默认删除this,当_M_weak_count为0时调用。
  • _M_add_ref_copy函数,对_M_use_count + 1,是原子操作。
  • _M_add_ref_lock函数,主要逻辑仍然是_M_use_count + 1。和_M_add_ref_copy的区别是对不同_Lock_policy有不同的实现,包含直接加、原子操作加、加锁。
  • _M_release函数,当_M_use_count-1=0时,即_M_use_count为0时,调用_M_dispose。并当_M_use_count-1=0,即_M_weak_count为0时,调用_M_destroy
  • _M_weak_add_ref:对_M_weak_count + 1,是原子操作。
  • _M_weak_release:只对_M_weak_count - 1
  • 以上两个函数都有_Lock_policy=_M_single时的重载形式。
_Sp_counted_ptr
// Counted ptr with no deleter or allocator support
template <typename _Ptr, _Lock_policy _Lp>
class _Sp_counted_ptr final : public _Sp_counted_base<_Lp> {
   
public:
    explicit _Sp_counted_ptr(_Ptr __p) noexcept : _M_ptr(__p) {
   }

    virtual void _M_dispose() noexcept {
    delete _M_ptr; }

    virtual void _M_destroy() noexcept {
    delete this; }

    virtual void* _M_get_deleter(const std::type_info&) noexcept {
    return nullptr; }

    _Sp_counted_ptr(const _Sp_counted_ptr&) = delete;
    _Sp_counted_ptr& operator=(const _Sp_counted_ptr&) = delete;

private:
    _Ptr _M_ptr;
};

template <>
inline void _Sp_counted_ptr<nullptr_t, _S_single>::_M_dispose() noexcept {
   }

template <>
inline void _Sp_counted_ptr<nullptr_t, _S_mutex>::_M_dispose() noexcept {
   }

template <>
inline void _Sp_counted_ptr<nullptr_t, _S_atomic>::_M_dispose() noexcept {
   }

不支持deleter和allocator的counted ptr。

  • _M_dispose默认行为是delete _M_ptr_M_destroy默认行为是delete this。
  • 对于_Ptr=nullptr_t时,不同_Lock_policy_M_dispose的行为都是空的。
_Sp_ebo_helper
template <int _Nm, typename _Tp, bool __use_ebo = !__is_final(_Tp) && __is_empty(_Tp)>
struct _Sp_ebo_helper;

/// Specialization using EBO.
template <int _Nm, typename _Tp>
struct _Sp_ebo_helper<_Nm, _Tp, true> : private _Tp {
   
    explicit _Sp_ebo_helper(const _Tp& __tp) : _Tp(__tp) {
   }
    explicit _Sp_ebo_helper(_Tp&& __tp) : _Tp(std::move(__tp)) {
   }

    static _Tp& _S_get(_Sp_ebo_helper& __eboh) {
    return static_cast<_Tp&>(__eboh); }
};

/// Specialization not using EBO.
template <int _Nm, typename _Tp>
struct _Sp_ebo_helper<_Nm, _Tp, false> {
   
    explicit _Sp_ebo_helper(const _Tp& __tp) : _M_tp(__tp) {
   }
    explicit _Sp_ebo_helper(_Tp&& __tp) : _M_tp(std::move(__tp)) {
   }

    static _Tp& _S_get(_Sp_ebo_helper& __eboh) {
    return __eboh._M_tp; }

private:
    _Tp _M_tp;
};

在类型_Tp为final且empty的时候,使用ebo优化的类,即模板参数__use_ebo为true的时候。

  • 对于“空”类型,不存在私有变量,_S_get返回强转为_Tp类型的入参_Sp_ebo_helper
  • 对于“非空”类型,有一个_Tp类型的私有变量:_M_tp_S_get返回这个变量。
_Sp_counted_deleter
// Support for custom deleter and/or allocator
template <typename _Ptr, typename _Deleter, typename _Alloc, _Lock_policy _Lp>
class _Sp_counted_deleter final : public _Sp_counted_base<_Lp> {
   
    class _Impl : _Sp_ebo_helper<0, _Deleter>, _Sp_ebo_helper<1, _Alloc> {
   
        typedef _Sp_ebo_helper<0, _Deleter> _Del_base;
        typedef _Sp_ebo_helper<1, _Alloc> _Alloc_base;

    public:
        _Impl(_Ptr __p, _Deleter __d, const _Alloc& __a) noexcept
            : _Del_base(std::move(__d)), _Alloc_base(__a), _M_ptr(__p) {
   }

        _Deleter& _M_del() noexcept {
    return _Del_base::_S_get(*this); }
        _Alloc& _M_alloc() noexcept {
    return _Alloc_base::_S_get(*this); }

        _Ptr _M_ptr;
    };

public:
    using __allocator_type = __alloc_rebind<_Alloc, _Sp_counted_deleter>;

    // __d(__p) must not throw.
    _Sp_counted_deleter(_Ptr __p, _Deleter __d) noexcept : _M_impl(__p, std::move(__d), _Alloc()) {
   }

    // __d(__p) must not throw.
    _Sp_counted_deleter(_Ptr __p, _Deleter __d, const _Alloc& __a) noexcept : _M_impl(__p, std::move(__d), __a) {
   }

    ~_Sp_counted_deleter() noexcept {
   }

    virtual void _M_dispose() noexcept {
    _M_impl._M_del()(_M_impl._M_ptr); }

    virtual void _M_destroy() noexcept {
   
        __allocator_type __a(_M_impl._M_alloc());
        __allocated_ptr<__allocator_type> __guard_ptr{
   __a, this};
        this->~_Sp_counted_deleter();
    }

    virtual void* _M_get_deleter(const type_info& __ti [[__gnu__::__unused__]]) noexcept {
   
#if __cpp_rtti
        // _GLIBCXX_RESOLVE_LIB_DEFECTS
        // 2400. shared_ptr's get_deleter() should use addressof()
        return __ti == typeid(_Deleter) ? std::__addressof(_M_impl._M_del()) : nullptr;
#else
        return nullptr;
#endif
    }

private:
    _Impl _M_impl;
};

_Impl继承自_Sp_ebo_helper<0, _Deleter>作为_Del_base_Sp_ebo_helper<1, _Alloc>作为_Alloc_base

  • _M_ptr作为私有变量是被管理的对象的指针。
  • _M_del_Del_base获取一个_Deleter变量。
  • _M_alloc_Alloc_base获取一个_Alloc类型变量。

_Sp_counted_deleter继承自_Sp_counted_base

  • 唯一的私有变量是_Impl类型的。
  • 构造函数主要是将传入的数据构造一个_Impl
  • _M_dispose函数对_Ptr调用_M_del()
  • _M_destroy函数对this调用析构函数。
  • _M_get_delter,当传入的type_info类型的__ti_Deleter是同样的类型的时候,返回_M_del()的地址,否则返回nullptr。
_Sp_counted_ptr_inplace
struct _Sp_make_shared_tag {
   
private:
    template <typename _Tp, typename _Alloc, _Lock_policy _Lp>
    friend class _Sp_counted_ptr_inplace;

    static const type_info& _S_ti() noexcept _GLIBCXX_VISIBILITY(default) {
   
        alignas(type_info) static constexpr char __tag[sizeof(type_info)] = {
   };
        return reinterpret_cast<const type_info&>(__tag);
    }

    static bool _S_eq(const type_info&) noexcept;
};

template <typename _Alloc>
struct _Sp_alloc_shared_tag {
   
    const _Alloc& _M_a;
};

template <typename _Tp, typename _Alloc, _Lock_policy _Lp>
class _Sp_counted_ptr_inplace final : public _Sp_counted_base<_Lp> {
   
    class _Impl : _Sp_ebo_helper<0, _Alloc> {
   
        typedef _Sp_ebo_helper<0, _Alloc> _A_base;

    public:
        explicit _Impl(_Alloc __a) noexcept : _A_base(__a) {
   }

        _Alloc& _M_alloc() noexcept {
    return _A_base::_S_get(*this); }

        __gnu_cxx::__aligned_buffer<_Tp> _M_storage;
    };

public:
    using __allocator_type = __alloc_rebind<_Alloc, _Sp_counted_ptr_inplace>;

    // Alloc parameter is not a reference so doesn't alias anything in __args
    template <typename... _Args>
    _Sp_counted_ptr_inplace(_Alloc __a, _Args&&... __args) : _M_impl(__a) {
   
        // _GLIBCXX_RESOLVE_LIB_DEFECTS
        // 2070.  allocate_shared should use allocator_traits<A>::construct
        allocator_traits<_Alloc>::construct(__a, _M_ptr(),
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值