【问题标题】:boost::shared_ptr is it safe to use it in multiple threads?boost::shared_ptr 在多个线程中使用它是否安全?
【发布时间】:2012-07-14 13:30:49
【问题描述】:

我试图找到答案一段时间但我失败了。

假设我们有一个从一个线程创建的shared_ptr。然后我们将这个 shared_ptr 传递给另外 2 个线程(例如使用一些队列)。所以从这一刻起,原始shared_ptr 有2 个副本,指向同一个原始指针。 两个所有者线程都将从队列中获取此shared_ptr 的副本。然后他们会将其传递给另一个线程或将其销毁。

问题是 - 它安全吗?原始指针是否会正确销毁(不会有引用计数器的竞争?)

【问题讨论】:

  • 您的表述有点模糊:“销毁”是指调用reset、分配新的指针还是让shared_ptr 超出范围?如果是这样,这些操作就很好。其他破坏性操作可能不是。
  • 我不打算调用任何 reset()。 shared_ptr 超出范围。

标签: c++ multithreading boost shared-ptr


【解决方案1】:

C++ 标准几乎不保证线程安全。 std::shared_ptr 的引用计数是唯一的例外:它保证表现为原子访问的变量。我相信这已编入第 20.7.2.2/4 节中的这句话中:

use_count() 中的更改不反映可能引入数据竞争的修改。

boost::shared_ptroffers the same guarantees:

shared_ptr 对象提供与内置类型相同级别的线程安全。一个 shared_ptr 实例可以被多个线程同时“读取”。不同的 shared_ptr 实例可以被多个线程同时“写入”……(即使这些实例是副本,并且在下面共享相同的引用计数。)

【讨论】:

  • OP 正在询问boost::shared_ptr。我希望行为会相同,但最好清楚一点。
  • @juan 好电话,但您提供的链接明确表示 OP 想要使用的操作是安全的。
  • 20.7.2.5 在这里也很有趣:“如果访问仅通过本节中的函数完成并传递实例,则从多个线程对 shared_ptr 对象的并发访问不会引入数据竞争作为他们的第一个论点。”
  • 没有对shared_ptr 的具体保证。该保证适用于每个标准等级。
  • "shared_ptr 保证具有原子引用计数" 不。明确不能保证shared_ptr 甚至使用计数器。 “没有其他标准类具有类似的保证” 不。其他所有 C++ 构造,无论是核心还是库,都提供完全相同的保证:实现不应引入数据竞争(当然,如果源代码中没有)。 “没有其他标准类描述包含与 §20.7.2.2/4 相当的措辞,”甚至 try_lock?
【解决方案2】:

boost docs 状态:

不同的 shared_ptr 实例可以同时被多个线程“写入”(使用诸如 operator= 或 reset 等可变操作进行访问)(即使这些实例是副本,并且在下面共享相同的引用计数。)

(强调我的)

所以这里的关键是你是否复制线程之间的boost::shared_ptrs。如果您创建副本(使用shared_ptrs 的“安全”方式),您不必担心线程安全。但是,如果您通过引用或指针传递 shared_ptr,因此在不同线程中使用实际相同的 shared_ptr,您将不得不担心线程安全,如文档中所述。

【讨论】:

  • 我创建副本并将它们放在线程队列中。然后从队列中取出副本。
【解决方案3】:

我想就多线程用例中的 boost 共享指针中的引用计数发表评论。评论是为了回答“boost共享指针引用计数中是否存在竞态条件?”的问题

对于大多数主流编译器,至少在 boost 1.35 之后,我的简单回答是“否”。在 boost/detail/shared_count.hpp 中定义的名为“add_ref_copy”的 boost 实现。该函数将调用为各个编译器定义的相应原子函数。例如windows版本会调用“BOOST_INTERLOCKED_INCREMENT”以原子方式递增计数(详见详细信息\sp_counted_base_w32.hpp)。 X86 的 Linux gcc 将调用 atomic_increment(... ) (详见详细信息\sp_counted_base_gcc_x86.hpp)。每个单独的编译器都实现了线程安全机制,以确保引用计数以有效的方式更新。有些代码甚至是用汇编编写的。

现在我的简单回答中有一个警告。您确实需要确保您的编译器包含在 boost 的祝福列表中,以实现多线程安全引用计数。如果您不确定是否可以定义“BOOST_SP_USE_PTHREADS”,它会驱动 boost 使用 pthread 库以原子方式更新引用计数(通过为 pthread 解决方案包含 boost/detail/sp_counted_base_pt.hpp)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-05
    • 2013-01-07
    • 1970-01-01
    相关资源
    最近更新 更多