免责声明:Boost和C ++ 11都不允许。
我有一个程序,我在其中创建Foo
的实例,并在多个线程中使用它。然后我想要安全地删除它,这样那些线程就不会陷入分段错误。
我已经为Foo
添加了一个互斥锁成员,并在每次线程函数运行时锁定它。为了使不同的线程不相互冲突。
class Foo
{
public:
pthread_mutex_t mutex;
};
void* thread ( void* fooPtr )
{
Foo* fooPointer = (Foo*) fooPtr;
while ( 1 )
{
if ( fooPointer )
{
pthread_mutex_lock ( &fooPointer->mutex );
/* some code, involving fooPointer */
pthread_mutex_unlock ( &fooPointer->mutex );
}
else
{
pthread_exit ( NULL );
}
}
}
现在我想要安全地删除foo
,以便线程中不会发生错误。我在Foo
添加了一个析构函数:
Foo::~Foo()
{
pthread_mutex_lock ( &mutex );
}
现在,在所有线程完成当前循环之前,不会删除该对象。
问题是:删除实例后是否会解锁互斥锁?删除实例后,所有线程都会完成吗?我打赌答案是no
。所以我改变了析构函数,但现在看起来线程不安全了:
Foo::~Foo()
{
pthread_mutex_lock ( &mutex );
pthread_mutex_unlock ( &mutex );
}
线程函数是否可以锁定互斥锁并在pthread_mutex_unlock ( &mutex );
之后开始操作实例并删除对象之前?
答案 0 :(得分:10)
让我们从问题的开头开始:
我有一个程序,在其中我创建了一个Foo实例并且我运行 在许多线程中使用它。然后我想安全删除它 这些线程不会陷入分段错误。
您无法删除正在使用的对象。没有多少互斥量可以解决这个问题。
我在Foo中添加了一个析构函数
仅在删除Foo
时运行。但是它的内容并不重要:当其他线程仍在使用Foo时调用dtor是错误的。
我希望在删除实例时安全退出线程。怎么可能?
嗯,这是正确的问题。我可以编写大量代码供您使用,但该代码只是boost::weak_ptr
的副本。所以,我不会打扰。只需自己动手代码即可。
不允许提升。
那你为什么要问StackOverflow?这基本上是相同的许可证。
答案 1 :(得分:1)
这里缺少的是指示线程处理完成时的条件。删除特定对象实例不是一个好条件。您还没有向我们展示删除对象的位置。如果我们可以在代码中看到这一点,那么额外的上下文会有所帮助。
我建议不是删除对象,而是在对象上设置一个标志(例如bool active())。然后,所有线程都将检查此标志,当它指示停止处理时,线程将停止。设置此标志,您当前正在删除Foo对象。然后,一旦所有线程都停止,删除Foo对象。
如果删除对象并期望能够获取其互斥锁,则可能会发生崩溃,或者至少是不稳定的行为,因为互斥锁是Foo的成员,并且它将随对象一起被破坏
这是我的意思的一个例子:
class Foo
{
public:
void lockMutex();
void unlockMutex();
// Active should be mutex protected as well
// Or you could consider using a pthread_rwlock
bool active() {return active_;}
void setActive(bool a) {active_ = a;}
private:
pthread_mutex_t mutex;
bool active_;
};
void* thread ( void* fooPtr )
{
Foo* fooPointer = (Foo*) fooPtr;
while ( 1 )
{
if ( fooPointer->active() )
{
fooPointer->lockMutex();
/* some code, involving fooPointer */
fooPointer->unlockMutex();
}
else
{
pthread_exit ( NULL );
}
}
// somewhere else in the code
fooPointer->setActive(false);
}
Foo :: setActive(true)必须在构造函数中调用,或者在创建对象时调用。一旦线程停止,就应该删除Foo对象,很可能是在pthread_join()完成之后。
答案 2 :(得分:-1)
你发布的代码不正确,因为c ++对象被步骤打破:
obj->Foo::~Foo();
free memory //maybe delete if allocated by new
所以你的源只是对析构函数进行原型化,而不是自由内存。
也许后面的源代码可以帮助你,它简单粗暴,但我认为它可以工作
class Foo
{
public:
void dosomething() {}
};
template<typename T>
class Protect
{
public:
struct auto_lock {
auto_lock(pthread_mutex_t& mutex)
: _mutex(mutex)
{
pthread_mutex_lock ( &_mutex );
}
~ auto_lock()
{
pthread_mutex_unlock ( &_mutex );
}
pthread_mutex_t& _mutex;
};
Protect(T*& p): _p(p) {}
T* get() { return _p; }
void lock() { pthread_mutex_lock ( &_mutex ); }
void unlock() { pthread_mutex_unlock ( &_mutex );}
pthread_mutex_t& getlock() { return _mutex; }
void safe_release() {
auto_lock l(_mutex);
if (_p != NULL) {
delete _p;
_p = NULL;
}
}
private:
T*& _p;
pthread_mutex_t _mutex;
};
void* thread ( void* proPtr )
{
Protect<Foo>* proPointer = (Protect<Foo>*) proPtr;
while ( 1 )
{
Protect<Foo>::auto_lock l(proPointer->getlock());
Foo* fooPtr = proPointer->get();
if ( fooPtr )
{
fooPtr->dosomething();
}
else
{
pthread_exit ( NULL );
}
}
}