shared_ptr线程安全的开销是多少?

What's the overhead from shared_ptr being thread-safe?

本文关键字:开销 多少 安全 ptr 线程 shared      更新时间:2023-10-16

std::shared_ptr保证是线程安全的。我不知道典型的实现使用什么机制来确保这一点,但肯定会有一些开销。即使在应用程序是单线程的情况下,这种开销也会存在。

是上述情况吗?如果是这样的话,如果你没有使用线程安全保证,这是否意味着它违反了"你不为你不使用的东西付费"的原则?

如果我们查看std::shared_ptr的cppreference页面,它们会在实现说明部分中声明以下内容:

为了满足线程安全要求,引用计数器通常使用std::atomic::fetch_add和std::memory_order_relaxed进行递增和递减。

注意一个实际的实现是很有趣的,例如这里的libstdc++实现文档说:

对于libstdc++中shared_ptr的版本,编译器和库是固定的,这使事情变得更简单:我们有一个原子CAS或我们没有,请参阅下面的锁定策略以了解详细信息。

选择锁定策略部分显示(强调矿):

有一个_Sp_counted_base类,它是一个模板在枚举__gn_cxx::_Lock_policy上参数化。整个家庭的类在锁策略上参数化,直到__shared_ptr、__weak_ptr和__enable_shared_from_this。实际的std::shared_ptr类通过锁定策略从__shared_ptr继承基于线程模型自动选择的参数,以及为其配置libstdc++的平台,以便获得最佳可用将使用模板专用化。这种设计是必要的,因为sharedptr有一个额外的模板是不符合要求的参数,即使它有默认值。可用的策略有:

[…]

3._S_单

此策略使用不带锁定的不可重入add_ref_lock()。当在没有--enable线程的情况下构建libstdc++时,将使用它。

并进一步表示(强调矿):

对于所有三个策略,引用计数的增量和减量分别为通过ext/atomicity.h中的函数完成,这些函数检测程序是否是多线程的如果则使用成本较低的非原子操作

所以,至少在这个实现中,你不会为你不使用的东西付费。

至少在i386上的boost代码中,boost::shared_ptr是使用原子CAS操作实现的。这意味着,虽然它有一些开销,但它相当低。我希望std::shared_ptr的任何实现都是类似的。

在高性能数字代码的紧密循环中,我发现切换到原始指针并非常小心会加快速度。但对于普通代码,我不会担心。