【问题标题】:Overhead and implementation of using shared_ptr使用 shared_ptr 的开销和实现
【发布时间】:2012-06-05 17:45:07
【问题描述】:

简短介绍:我正在处理多线程代码,我必须在两个线程之间共享动态分配的对象。为了使我的代码更简洁(并且不易出错),我想在每个线程中显式“删除”对象,这就是我想使用shared_ptr 的原因。

第一个问题:

我想知道在运行时shared_ptr 中的-> operator 的实现是否有一些额外的开销(例如大于unique_ptr)。我所说的对象通常是 longlife 实例,在创建后只复制一次(当我在线程之间分发它们时),然后我只访问这些对象的方法和字段。

我知道,shared_ptr 只保护引用计数。

第二个问题:

shared_ptr 在 libstdc++ 中的优化程度如何?它总是使用互斥锁还是利用原子操作(我专注于 x86 和 ARM 平台)?

【问题讨论】:

  • shared_ptr 的良好实现中,通过-> 取消引用指针时应该有零开销。我不熟悉 libstdc++,所以我无法回答你的第二个问题。不过,您有标题,因此您可以通过查看它的实现方式轻松找到。
  • 如果代码是多线程的,GCC 的共享指针使用std::atomic<int> 或类似的东西作为引用计数器;这是否是真正的硬件(无锁)原子取决于编译器版本——我相信这在 GCC 4.7.0 中得到了改进。
  • 复制/赋值/超出范围有额外的开销,因为引用计数的线程安全增量。 operator-> 看起来与旧的 auto_ptr 完全相同,即可以预期开销为零。
  • 这个问题目前的形式过于宽泛,无法回答。 shared_ptr的实现有很多,GCC和libstdc++的版本也很多。你说的是哪一个?

标签: c++ c++11 shared-ptr


【解决方案1】:

第一个问题:使用operator->

我见过的所有实现在shared_ptr<T> 类中都有一个T* 的本地缓存,因此该字段在堆栈上,operator-> 因此与使用堆栈本地T* 的成本相当:完全没有开销。

第二个问题:互斥体/原子

我希望 libstdc++ 在 x86 平台上使用原子,无论是通过标准工具还是特定的 g++ 内在函数(在旧版本中)。我相信 Boost 实现已经这样做了。

但是,我不能对 ARM 发表评论。

注意:C++11引入了移动语义,shared_ptr的使用自然避免了很多副本。

注意:阅读有关shared_ptrhere 的正确用法,您可以使用对shared_ptrconst 或否)的引用来避免大多数复制/破坏,因此性能这些都不是很重要。

【讨论】:

  • 在您附加的答案中,据说使用make_shared。我想知道如何在构造函数的初始化列表中使用这个模板?例如,类Foo 具有字段shared_ptr<int> num,因此构造函数应如下所示:Foo::Foo(void) : num (move (make_shared (new int (30)))) { ... }?
  • @Goofy: 不,make_shared 不会显式执行new,另一方面,您需要显式传递创建对象的类型;也不需要临时调用move。因此它产生:Foo::Foo(): num(std::make_shared<int>(30)) {}
  • 好的,太好了 :) 我还在习惯 C++ 中的右值 ;)
【解决方案2】:

GCC 的 shared_ptr 将在单线程代码中不使用锁定或原子。在多线程代码中,如果 CPU 支持原子比较和交换指令,它将使用原子操作,否则引用计数受互斥体保护。在 i486 和更高版本上它使用原子,i386 不支持 cmpxchg 因此使用基于互斥锁的实现。我相信 ARM 将原子用于 ARMv7 架构及更高版本。

(同样适用于std::shared_ptrstd::tr1::shared_ptr。)

【讨论】:

  • GCC 如何知道代码是否/将是多线程的?
  • @DrewNoakes - 你必须用#define 告诉它。
  • @Jonathan Wakely 是 libstdc++ 的实现者之一。不过,如果你能详细说明一下,我也会觉得很好,比如定义是什么,默认是什么?
  • 没有#define。 Libstdc++ 使用基于程序是否链接到libpthread 来分派(在运行时)到原子实现或非原子实现的函数。如果它链接到libpthread,则假定存在多个线程并使用原子实现。如果未链接到libpthread,则程序是单线程的,因此使用非原子 impl。
  • 在“选择锁定策略”部分的gcc.gnu.org/onlinedocs/libstdc++/manual/… 有一些简短的文档
猜你喜欢
  • 2020-11-19
  • 2010-10-27
  • 1970-01-01
  • 1970-01-01
  • 2023-02-08
  • 2022-01-02
  • 2013-01-29
  • 2022-01-09
  • 1970-01-01
相关资源
最近更新 更多