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_ptr
s 指向具有共享内部引用计数的同一个共享对象的情况。它不适用于对同一 shared_ptr
的并发访问。
请注意,c++11 定义了atomics for shared_ptr<>
too(它可能是也可能不是std::atomic_is_lock_free
。所以有一个可能的解决方案不使用重量级(例如互斥锁)。以上是关于shared_ptr.get() 是不是可以被多个线程调用,而另一个线程锁定并调用 shared_ptr.swap()?的主要内容,如果未能解决你的问题,请参考以下文章
泛化共享指针和 QSharedPointer::data() vs shared_ptr::get()?