如何使用 boost::shared_ptr 安全地释放线程之间共享的对象
How do I safely release an object shared between threads using boost::shared_ptr?
我想知道,这样实现安全吗?
typedef shared_ptr<Foo> FooPtr;
FooPtr *gPtrToFooPtr // global variable
// init (before any thread has been created)
void init()
{
gPtrToFooPtr = new FooPtr(new Foo);
}
// thread A, B, C, ..., K
// Once thread Z execute read_and_drop(),
// no more call to read() from any thread.
// But it is possible even after read_and_drop() has returned,
// some thread is still in read() function.
void read()
{
FooPtr a = *gPtrToFooPtr;
// do useful things (read only)
}
// thread Z (executed once)
void read_and_drop()
{
FooPtr b = *gPtrToFooPtr;
// do useful things with a (read only)
b.reset();
}
我们不知道哪个线程会做实际的实现。在这种情况下,boost shared_ptr
安全地发布吗?
根据boost的文档,shared_ptr
线程的安全性是:
可以"读取"
shared_ptr
实例(仅使用 const 访问) 操作)同时由多个线程执行。不同shared_ptr
实例可以"写入"(使用可变操作访问,例如 作为运算符=
或reset
)同时由多个线程。
就我而言,上面的代码没有违反我上面提到的任何线程安全标准。我相信代码应该运行良好。有人告诉我是对还是错吗?
提前谢谢。
已编辑 2012-06-20 01:00 UTC+9
上面的伪代码工作正常。shared_ptr
实现保证在多个线程访问其实例的情况下正常工作(每个线程必须访问其自己的使用复制构造函数实例化shared_ptr
实例)。
请注意,在上面的伪代码中,您必须delete gPtrToFooPtr
让shared_ptr
实现最终释放(将引用计数删除一个)它拥有的对象(不是正确的表达式,因为它不是auto_ptr
,但谁在乎;))。在这种情况下,您必须意识到它可能会导致多线程应用程序中的 SIGSEGV。
你在这里如何定义"安全"?如果您将其定义为"我想确保对象只销毁一次",那么是的,发布是安全的。但是,问题是在您的示例中,两个线程共享一个智能指针。这根本不安全。一个线程执行的reset()
可能对另一个线程不可见。
如文档所述,智能指针提供与内置类型(即指针)相同的保证。因此,在其他线程可能仍在读取时执行不受保护的写入是有问题的。当另一个读取线程将看到另一个读取线程的写入时,它是未定义的。因此,当一个线程调用reset()
指针可能不会在另一个线程中重置,因为shared_ptr实例本身是共享的。
如果需要某种线程安全性,则必须使用两个共享指针实例。然后,当然,重置其中一个不会释放对象,因为另一个线程仍然有对它的引用。通常这种行为是有意的。
但是,我认为更大的问题是您滥用了shared_ptrs。使用shared_ptrs指针并在堆上分配shared_ptr(使用 new)是非常罕见的。如果这样做,则会遇到要避免再次使用智能指针的问题(现在必须管理shared_ptr的生命周期)。也许先查看一些关于智能指针及其用法的示例代码。
为了你好,我会说实话。
你的代码做了很多事情,几乎所有的事情都是无用和荒谬的。
typedef shared_ptr<Foo> FooPtr;
FooPtr *gPtrToFooPtr // global variable
指向智能指针的原始指针取消了自动资源管理的优势,并且不能解决任何问题。
void read()
{
FooPtr a = *gPtrToFooPtr;
// do useful things (read only)
}
a
不会以任何有意义的方式使用。
{
FooPtr b = ...
b.reset();
}
b.reset()
在这里没用,反正b
就要被摧毁了。 b
在此函数中没有用途。
恐怕你不知道你在做什么,智能指针是干什么的,如何使用shared_ptr
,如何做MT编程;所以,你最终会得到一堆荒谬的无用功能来解决问题。
简单地做简单的事情怎么样:
Foo f;
// called before others functions
void init() {
// prepare f
}
// called in many threads {R1, R2, ... Rn} in parallel
void read()
{
// use f (read-only)
}
// called after all threads {R1, R2, ... Rn} have terminated
void read_and_drop()
{
// reset f
}
在可以保证其他线程不读取f
之前,不得调用read_and_drop()
。
要编辑:
为什么不在全球shared_ptr
上首先致电reset()
?
- 如果您是最后一个访问该对象的人,则将其删除,然后删除堆上的
shared_ptr
。 - 如果其他线程仍在使用它,则将 ref 计数减少 1,并将全局 ptr 与指向的(仍然存在的)对象"断开连接"。然后,您可以安全地删除堆上的
shared_ptr
,而不会影响可能仍在使用它的任何线程。
- 从不同线程使用int64的不同字节安全吗
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- 多个线程之间的获取-释放内存顺序
- 如何使用 boost::shared_ptr 安全地释放线程之间共享的对象
- join() 是否释放了分配的内存?- C++11 线程
- 如何在 Windows 上的线程退出时释放 TLS 插槽中的对象
- 如何释放线程本地存储的堆内存
- 释放信号量后立即启动的线程
- C++线程错误:未分配要释放的指针
- 为什么 std::atomic 初始化不执行原子释放,以便其他线程可以看到初始化的值?
- 释放模式下的boost线程崩溃
- malloc_trim(0)释放线程竞技场的fastbin
- 创建boost线程时,Shared_ptr永远不会释放
- c++中分离线程的资源释放
- 在不同的线程上安全地释放资源
- 如果一个线程在临界区上调用Acquire(),如果另一个线程调用Release(),该锁会被释放吗?
- 在运行循环外声明、分配和释放线程局部指针变量
- Boost线程:释放后被修改的对象
- 如何为多个线程创建临时数组,而不需要不断地分配和释放
- 从您无法控制且无权访问的线程中释放 Python 导入锁