You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

探究std::weak_ptr::lock()实现:如何保证多线程无额外同步使用

如何实现std::weak_ptr::lock()以保证跨线程无额外同步安全使用shared_ptr与weak_ptr

根据cppreference的说明:

std::weak_ptr<T>::lock 实际上会原子执行 expired() ? shared_ptr() : shared_ptr(*this)。

示例代码

#include<memory>
#include<thread>

std::shared_ptr<int> g_s = std::make_shared<int>(1);
std::weak_ptr<int> w_p{g_s};

void f1(std::weak_ptr<int>& wp)
{
    std::shared_ptr<int> l_s1 = wp.lock(); // 读取 g_s
}

void f2()
{
    std::shared_ptr<int> l_s2 = std::make_shared<int>(3);
    std::thread th(f1, std::ref(w_p));
    th.detach();
    g_s = l_s2; // 修改 g_s
}

int main()
{
    std::thread(f2).join();
}

GCC中的具体实现(基于libstdc++)

在GCC的shared_ptr.h和shared_ptr_base.h头文件中,lock()的核心实现如下:

// __shared_ptr版本的lock
__shared_ptr<_Tp, _Lp>
weak_ptr::lock() const noexcept
{ return __shared_ptr<element_type, _Lp>(*this, std::nothrow); }

// shared_ptr版本的lock
shared_ptr<_Tp>
weak_ptr::lock() const noexcept
{ return shared_ptr<_Tp>(*this, std::nothrow); }

关键构造逻辑解析

lock()本质是通过带std::nothrow参数的shared_ptr构造函数实现安全升级:

  1. 从weak_ptr构造shared_ptr的核心逻辑
/**
 * @brief 构造一个与__r共享所有权的shared_ptr,并复制__r中存储的指针
 * @param __r 一个weak_ptr
 * @post use_count() == __r.use_count()
 * @throw 当__r已过期时抛出bad_weak_ptr,此时构造函数无效果
 */
template<typename _Yp, typename = _Constructible<const weak_ptr<_Yp>&>>
explicit shared_ptr(const weak_ptr<_Yp>& __r)
: __shared_ptr<_Tp>(__r) { }

// 底层__shared_ptr的构造实现
template<typename _Yp, typename = _Compatible<_Yp>>
explicit __shared_ptr(const __weak_ptr<_Yp, _Lp>& __r)
: _M_refcount(__r._M_refcount) // 可能抛出异常
{
  // 由于_M_refcount(__r._M_refcount)未抛出,此时复制__r._M_ptr是安全的
  _M_ptr = __r._M_ptr;
}

这里的核心是先原子操作引用计数:构造_M_refcount时会尝试将弱引用计数升级为强引用计数,这一步是原子的。只有当升级成功(即对象未过期),才会复制对象指针_M_ptr,避免了指针被释放后访问的风险。

  1. weak_ptr的构造安全处理
    针对多线程场景下weak_ptr的拷贝,GCC做了特殊处理:
// 注释说明:"直观"的转换构造函数实现存在严重问题
// __r._M_ptr可能已失效,转换时可能需要访问*__r._M_ptr(比如虚继承场景)
// 多线程中__r._M_ptr随时可能失效,无法避免虚假访问违规

template<typename _Yp, typename = _Compatible<_Yp>>
__weak_ptr(const __weak_ptr<_Yp, _Lp>& __r) noexcept
: _M_refcount(__r._M_refcount)
    { _M_ptr = __r.lock().get(); }

这里先拷贝原子安全的引用计数_M_refcount,再通过lock()获取有效的对象指针,避免直接拷贝可能已失效的_M_ptr。

  1. 从shared_ptr构造weak_ptr的逻辑
template<typename _Yp, typename = _Compatible<_Yp>>
__weak_ptr(const __shared_ptr<_Yp, _Lp>& __r) noexcept
: _M_ptr(__r._M_ptr), _M_refcount(__r._M_refcount)
{ }

此时shared_ptr的对象肯定有效,因此可以直接拷贝指针和引用计数,无需额外安全处理。


内容的提问来源于stack exchange,提问作者John

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 11:50:55