C++智能指针是否锁定?

5
以下操作对于 std::unique_ptr 和/或 std::shared_ptr 是否是无锁的呢?
  1. 解引用,例如 read(*myPtr) 或者 myPtr->getSomething()
  2. 移除引用,例如使用 std::move(myUniquePtr) 或当一个 std::shared_ptr 超出作用域时。
在我的情况下,我不会从多个线程同时访问这些指针。我只是好奇是否可以在高优先级、无锁线程上专门使用它们。由指针管理的对象是由主线程在高优先级回调之前分配的,并且在回调停止之前不会被释放。
谢谢!

请使用这些http://en.cppreference.com/w/cpp/memory/shared_ptr/atomic。 - Bryan Chen
请注意,“move”和超出范围是非常不同的概念。 “move”永远不会改变引用计数。 - Yakk - Adam Nevraumont
@bryanchen,这些是针对多线程一个变量的情况,不过我认为这不是OP所讨论的。 - Yakk - Adam Nevraumont
@Yakk不是将引用从源unique_ptr中删除并添加到目标unique_ptr中吗?我在与移动unique_ptr相关的错误中看到了std::remove_reference - mxdubois
@mxdubois 当然,unique_ptr 没有必要加锁:它没有显著的争用。对于 shared,您可以将引用移动到目标位置,而无需进行 +1 -1 的混乱...完全不会干扰源控制块内容!不过,目标位置确实需要一个非空的 .reset(),这是需要注意的。 - Yakk - Adam Nevraumont
2个回答

5

合理实现的情况下,您可以假设:

std::unique_ptr:

  • 所有 std::unique_ptr 上的操作与原始指针上的相应操作一样无锁,因为并发方面没有特殊之处。

std::shared_ptr:

  • 所有不更改引用计数的操作都与原始指针上的相应操作一样无锁。这包括解引用移动构造等操作。
  • std::move 是无锁的,因为它只是将左值引用转换为右值引用。
  • std::shared_ptr 的析构函数至少与 std::atomic<std::size_t> 一样无锁(可以使用成员函数 is_lock_free 进行检查)。
  • 移动赋值取决于左侧的 std::shared_ptr 是否有关联的托管对象。如果有关联的托管对象,则与析构函数一样无锁。否则,它与移动构造函数一样无锁,因为引用计数不会改变。

我会接受Burr的答案,因为我主要是在寻找保证的内容,但还是感谢您提供额外的信息! - mxdubois

3
标准仅仅说明了对于shared_ptr<>(20.7.2.2/4 "Class template shared_ptr"):

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

它并没有说这些use_count()的更改必须是无锁的。标准允许使用互斥锁来防止数据竞争。 unique_ptr<>没有承诺防止数据竞争(它本身并不打算在多线程中安全使用)。

然而,在实践中,唯一有任何理由锁定的是“超出范围”的对象。 - Yakk - Adam Nevraumont
1
@mxdubois:我认为unique_ptr实现没有理由在解引用时引入锁,但我不确定标准是否禁止这样做。移动操作同理。 - Michael Burr
不能保证它是无锁的,但没有理由使用需要同步的实现。 - R. Martinho Fernandes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接