我想知道,这样实施是否安全? :
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();
}
我们不知道哪个线程会执行实际的realease。
在这样的情况下,boost shared_ptr
是否安全释放?
根据boost的文档,shared_ptr
的线程安全性是:
shared_ptr
实例可以“读取”(仅使用const访问) 操作)由多个线程同时进行。 不同shared_ptr
实例可以“写入”(使用可变操作访问) 作为运算符=
或reset
)同时由多个线程组成。
就我而言,上面的代码并没有违反我上面提到的任何线程安全标准。我相信代码应该运行良好。有人告诉我,我是对还是错?
提前致谢。
上面的伪代码工作正常。 shared_ptr
实现保证在多个线程访问它的实例的情况下正常工作(每个线程必须访问它自己的实例shared_ptr
使用复制构造函数实例化)。
请注意,在上面的伪代码中,您必须delete gPtrToFooPtr
让shared_ptr
实现最终释放(将引用计数减一)它拥有的对象(不是正确的表达式,因为它不是auto_ptr
,但谁在乎;))。在这种情况下,您必须意识到它可能会在多线程应用程序中导致SIGSEGV。
答案 0 :(得分:1)
你如何在这里定义'安全'?如果您将其定义为“我想确保对象被完全摧毁一次”,那么YES,该版本是安全的。但是,问题是两个线程在您的示例中共享一个智能指针。这根本不安全。一个线程执行的reset()
可能对另一个线程不可见。
如文档所述,智能指针提供与内置类型(即指针)相同的保证。因此,在其他线程可能仍在读取时执行无保护写入是有问题的。当其他读取线程看到另一个读写线程的写入时,它是未定义的。因此,当一个线程调用reset()
时,指针可能不会在另一个线程中重置,因为shared_ptr实例本身是共享的。
如果您想要某种线程安全性,则必须使用两个共享指针实例。然后,当然,重置其中一个将不会释放该对象,因为另一个线程仍然具有对它的引用。通常会出现这种行为。
但是,我认为更大的问题是你滥用shared_ptrs。使用shared_ptrs指针并在堆上分配shared_ptr(使用new)非常罕见。如果你这样做,你有问题想避免再次使用智能指针(你必须现在管理shared_ptr的生命周期)。也许首先查看一些关于智能指针及其用法的示例代码。
答案 1 :(得分:1)
为了你自己的利益,我会诚实。
你的代码做了很多事情,而且几乎所有事情都是无用且荒谬的。
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
}
read_and_drop()
之前不得调用可以保证其他线程无法读取f
。
答案 2 :(得分:-1)
进行编辑:
为什么不首先在全球reset()
上致电shared_ptr
?
shared_ptr
。 shared_ptr
,而不会影响仍可能使用它的任何线程。