我对boost::shared_ptr<T>
有疑问。
有很多帖子。
using namespace boost;
class CResource
{
// xxxxxx
}
class CResourceBase
{
public:
void SetResource(shared_ptr<CResource> res)
{
m_Res = res;
}
shared_ptr<CResource> GetResource()
{
return m_Res;
}
private:
shared_ptr<CResource> m_Res;
}
CResourceBase base;
//----------------------------------------------
// Thread_A:
while (true)
{
//...
shared_ptr<CResource> nowResource = base.GetResource();
nowResource.doSomeThing();
//...
}
// Thread_B:
shared_ptr<CResource> nowResource;
base.SetResource(nowResource);
//...
如果 Thread_A 不关心nowResource
是最新的,那么这部分代码会有问题吗?
我的意思是当 Thread_B 完全没有SetResource()
时, Thread_A 会在GetResource()
之前获得错误的智能点?
线程安全是什么意思?
如果我不关心资源是否最新,shared_ptr<CResource> nowResource
会在nowResource
被释放后崩溃,还是问题会破坏shared_ptr<CResource>
?
答案 0 :(得分:40)
boost::shared_ptr<>
提供一定程度的线程安全性。引用计数以线程安全的方式进行操作(除非您将boost配置为禁用线程支持)。
因此,您可以复制shared_ptr
,并正确维护ref_count。你不能在多个线程中安全地做的是从多个线程修改实际的shared_ptr
对象实例本身(例如从多个线程调用reset()
)。因此,您的使用不安全 - 您正在修改多个线程中的实际shared_ptr
实例 - 您需要拥有自己的保护。
在我的代码中,shared_ptr
通常是按值传递的本地或参数,因此没有问题。从一个线程到另一个线程我通常使用线程安全队列。
当然,这些都没有解决访问shared_ptr
指向的对象的线程安全问题 - 这也取决于你。
答案 1 :(得分:31)
来自提升documentation:
shared_ptr
个对象提供相同的功能 内置的线程安全级别 类型。一个shared_ptr
实例可以 “read”(仅使用const访问) 操作)同时多个 线程。 不同shared_ptr
实例可以“写入” (使用可变操作访问 例如operator=
或重置) 同时由多个线程 (即使这些实例是副本, 并分享相同的引用计数 的下面。)任何其他同时访问都会导致未定义的行为。
因此,您的使用不安全,因为它使用m_res
的同时读写。 boost文档中的示例3 也说明了这一点。
您应该使用单独的mutex来保护m_res
/ SetResource
中对GetResource
的访问权限。
答案 2 :(得分:3)
嗯,tr1 :: shared_ptr(基于boost)文档讲述了一个不同的故事,这意味着资源管理是线程安全的,而对资源的访问则不是。
” ...
线程安全
C ++ 0x-only功能包括:rvalue-ref / move support,allocator support,aliasing constructor,make_shared&amp; allocate_shared。此外,采用auto_ptr参数的构造函数在C ++ 0x模式下不推荐使用。
Boost shared_ptr文档的Thread Safety部分说“shared_ptr对象提供与内置类型相同的线程安全级别。”实现必须确保对单独的shared_ptr实例的并发更新是正确的,即使这些实例共享引用计数,例如。
shared_ptr a(新A); shared_ptr b(a);
//线程1 //线程2
a.reset(); b.reset();
动态分配的对象必须被其中一个线程销毁。弱引用使事情变得更有趣。用于实现shared_ptr的共享状态必须对用户透明,并且必须始终保留不变量。共享状态的关键部分是强弱参考计数。对这些线程的更新需要是原子的并且对所有线程都是可见的,以确保正确清理托管资源(毕竟,这是shared_ptr的工作!)在多处理器系统上,可能需要内存同步,以便引用计数更新和销毁托管资源是无竞争的。
...“
见 http://gcc.gnu.org/onlinedocs/libstdc++/manual/memory.html#std.util.memory.shared_ptr
答案 3 :(得分:1)
m_Res 不是线程安全的,因为它同时读/写, 你需要boost :: atomic_store / load函数来保护它。
//--- Example 3 ---
// thread A
p = p3; // reads p3, writes p
// thread B
p3.reset(); // writes p3; undefined, simultaneous read/write
答案 4 :(得分:-1)
添加,您的类具有循环引用条件; shared_ptr<CResource> m_Res
不能是CResourceBase
的成员。您可以改为使用weak_ptr
。