C++ 如何使用boost::shared\u ptr安全地释放线程之间共享的对象?
我想知道,这样实施安全吗C++ 如何使用boost::shared\u ptr安全地释放线程之间共享的对象?,c++,multithreading,boost,thread-safety,shared-ptr,C++,Multithreading,Boost,Thread Safety,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 // On
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();
}
typedef共享\u ptr FooPtr;
FooPtr*gPtrToFooPtr//全局变量
//init(在创建任何线程之前)
void init()
{
gptrtofootr=新FooPtr(新Foo);
}
//螺纹A、B、C、…、K
//一旦线程Z执行read_和_drop(),
//不再从任何线程调用read()。
//但即使在read_和_drop()返回后也有可能,
//某些线程仍在read()函数中。
无效读取()
{
FooPtr a=*gPtrToFooPtr;
//做有用的事情(只读)
}
//线程Z(执行一次)
无效读取和删除()
{
FooPtr b=*gPtrToFooPtr;
//使用(只读)命令执行有用的操作
b、 重置();
}
我们不知道哪个线程将执行实际的realess。
boost的shared\u ptr
在这种情况下发布安全吗
根据boost的文档,共享的线程安全性是:
shared_ptr
实例可以“读取”(仅使用常量访问)
操作)由多个线程同时执行不同共享
实例可以“写入”(使用可变操作访问),例如
as操作员通过多个线程同时执行=
或重置
)
就我而言,上面的代码没有违反我上面提到的任何线程安全标准。我相信代码应该运行良好。有人告诉我我是对还是错吗
提前谢谢
编辑日期2012-06-20 01:00 UTC+9 上面的伪代码运行良好。
shared_ptr
实现保证在多个线程正在访问其实例的情况下正常工作(每个线程必须访问其自己的shared_ptr
实例,该实例是使用复制构造函数实例化的)
注意,在上面的伪代码中,您必须
删除gPtrToFooPtr
,才能让共享ptr
实现最终释放(将引用计数减少一)它所拥有的对象(不是正确的表达式,因为它不是自动ptr
,但谁在乎呢;)。在这种情况下,您必须意识到,它可能会在多线程应用程序中导致SIGSEGV。这里如何定义“安全”?如果您将其定义为“我想确保对象只销毁一次”,那么是的,释放是安全的。但是,问题是在您的示例中,两个线程共享一个智能指针。这根本不安全。由一个线程执行的reset()
对另一个线程可能不可见
如文档所述,智能指针提供与内置类型(即指针)相同的保证。因此,在另一个线程可能仍在读取时执行无防护写入是有问题的。当另一个读取线程看到另一个线程的写入时,它是未定义的。因此,当一个线程调用reset()
如果需要某种线程安全性,则必须使用两个共享指针实例。当然,重置其中一个线程不会释放对象,因为另一个线程仍然有对它的引用。通常这种行为是故意的
然而,我认为更大的问题是您滥用了共享资源。使用共享\u ptr的指针并在堆上分配共享\u ptr(使用new)是非常少见的。如果您这样做,您就会遇到希望避免再次使用智能指针的问题(您现在必须管理共享\u ptr的生命周期)。也许可以先查看一些有关智能指针及其用法的示例代码。要编辑:
为什么不先在全局共享\u ptr
上调用reset()
- 如果您是最后一个访问该对象的人,那么它将被删除,然后您将删除堆上的
共享\u ptr
李>
- 如果其他线程仍在使用它,则将ref计数减少1,并将全局ptr与指向的(仍然存在)对象“断开”。然后,您可以安全地删除堆上的
共享\u ptr
,而不会影响可能仍在使用它的任何线程
为了你自己的利益,我会诚实的
你的代码做了很多事情,几乎所有的都是无用的和荒谬的
typedef shared_ptr<Foo> FooPtr;
FooPtr *gPtrToFooPtr // global variable
a
没有以任何有意义的方式使用
{
FooPtr b = ...
b.reset();
}
b.reset()
在这里是无用的,b
无论如何都将被销毁<代码>b
在此功能中没有任何用途
我恐怕你不知道你在做什么,智能指针的用途是什么,如何使用shared\u ptr
,以及如何进行机器翻译编程;因此,你最终会得到这堆荒谬的无用功能,而无法解决问题
简单地做简单的事情怎么样
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
那么,将全局共享的类型更改为,比如说,FooPtr gFooPtr代码>和,分配给FooPtr a=gFooPtr代码>和FooPtr b=gFooPtr代码>?我猜这与使用指向动态分配的共享\u ptr实例的指针相同。我认为,共享\u ptr的引用计数将阻止“无防护写入”,该引用计数由boost提供的无锁机制保护。因为只有在释放Foo实例时才可能进行写入,并且它受shared_ptr的引用计数保护。这样更好(请参阅我文章中的编辑,最好再阅读一遍)。但是,对象有两个引用,因此,仅重置其中一个引用不会释放对象。您必须在每个线程中重置指针。这通常是智能指针的预期行为:如果一个线程仍然有
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
}