shared_ptr.get() 是不是可以被多个线程调用,而另一个线程锁定并调用 shared_ptr.swap()?

Posted

技术标签:

【中文标题】shared_ptr.get() 是不是可以被多个线程调用,而另一个线程锁定并调用 shared_ptr.swap()?【英文标题】:Can shared_ptr.get() be called by multiple threads while another thread locks and calls shared_ptr.swap()?shared_ptr.get() 是否可以被多个线程调用,而另一个线程锁定并调用 shared_ptr.swap()? 【发布时间】:2014-09-01 04:14:32 【问题描述】:

我想知道使用 shared_ptr 是否安全。请原谅我的伪代码:

Thread 1:
do lock
ReadOnlyObj obj = make_shared<ReadOnlyObj>();
some_shared_ptr.swap(obj);
do unlock

Thread 2-N:
//no lock
some_shared_ptr->getterOnObj();

CPP 参考说

所有成员函数(包括复制构造函数和复制赋值)都可以由多个线程在 shared_ptr 的不同实例上调用而无需额外同步,即使这些实例是副本并共享同一对象的所有权。如果多个执行线程在没有同步的情况下访问同一个 shared_ptr 并且其中任何一个访问使用 shared_ptr 的非常量成员函数,则将发生数据竞争,可以使用原子函数的 shared_ptr 重载来防止数据竞赛。

但是,根据GNU docs:

Boost shared_ptr(在 GCC 中使用)具有巧妙的无锁算法来避免竞争条件,但这依赖于支持原子比较和交换指令的处理器。对于其他平台,有使用互斥锁的回退。 Boost(从 1.35 版开始)包括几种不同的实现,预处理器根据编译器、标准库、平台等选择一个。对于 libstdc++ 中 shared_ptr 的版本,编译器和库是固定的,这使得事情变得更加简单:我们有一个atomic CAS 或者我们没有,请参阅下面的锁定策略了解详细信息。

据我所知,intel x86_64 支持 CAS。

所以,对于我的问题:

shared_ptr::swap 是非常量的。 get 和 ->() 是常量。鉴于上面列出的使用场景,我是否也必须锁定 get/->?

【问题讨论】:

【参考方案1】:

我想我自己在boost docs.找到了答案

//--- Example 3 ---

// thread A
p = p3; // reads p3, writes p

// thread B
p3.reset(); // writes p3; undefined, simultaneous read/write

我正在尝试做的是同时读取和写入,这是未定义/不安全的。

【讨论】:

没错。 shared_ptr 的内部同步适用于您有两个不同的shared_ptrs 指向具有共享内部引用计数的同一个共享对象的情况。它不适用于对同一 shared_ptr 的并发访问。 请注意,c++11 定义了atomics for shared_ptr&lt;&gt; too(它可能是也可能不是std::atomic_is_lock_free。所以有一个可能的解决方案不使用重量级(例如互斥锁)。

以上是关于shared_ptr.get() 是不是可以被多个线程调用,而另一个线程锁定并调用 shared_ptr.swap()?的主要内容,如果未能解决你的问题,请参考以下文章

泛化共享指针和 QSharedPointer::data() vs shared_ptr::get()?

这个类被标记为“@immutable”,但它的一个或多个实例字段不是最终的:

GAC中的库被多个应用程序使用,它是不是共享相同的对象?

远程桌面连接可以允许多个用户和本机同时登陆吗?

多个用户访问同一段代码

为不同的用户创建多个表是不是更有效?