我正在尝试编写一个在其对象创建时运行线程的类,并在对象被删除后停止该线程。
class MyThread : public boost::thread {
public:
MyThread() : bAlive(true) {
boost::thread(&MyThread::ThreadFunction,this);
}
~MyThread() {
{
boost::unique_lock<boost::mutex> lock(Mutex);
bAlive=false;
}
ConditionVariable.notify_one();
join();
}
private:
volatile bool bAlive;
boost::mutex Mutex;
boost::condition_variable ConditionVariable;
void ThreadFunction() {
boost::unique_lock<boost::mutex> lock(Mutex);
while(bAlive) {
ConditionVariable.timed_wait(lock,boost::get_system_time()+ boost::posix_time::milliseconds(MAX_IDLE));
/*******************************************
* Here goes some code executed by a thread *
*******************************************/
}
}
};
理论上,我想在需要完成后立即唤醒线程,所以我不得不使用timed_wait而不是Sleep。 这工作正常,直到我尝试删除此类的对象。在大多数情况下,它会正常删除,但偶尔会在condition_variable.hpp,thread_primitives.hpp或crtexe.c中导致错误。有时我会收到通知“自由堆块3da7a8在被释放后在3da804处被修改”,有时我不是。是的,我知道timed_wait的虚假唤醒,在这种情况下它并不重要。 你能指点我的问题来源吗?我做错了什么?
答案 0 :(得分:1)
我看到你正在尝试做什么,但它没有像你期望的那样工作:
MyThread foo;
默认构造一个boost :: thread(因为MyThread是从boost :: thread派生的)。 默认构造函数创建一个引用非线程的boost :: thread实例。
MyThread() {
boost::thread(&MyThread::ThreadFunction,this);
}
实际上是在创建一个不同的线程而你忽略了返回的对象(有效的线程)。
~MyThread() {
// ...
join();
}
然后尝试加入默认构造的线程(在析构函数中引发异常),你永远不会加入实际工作的线程。
首先,不要从boost :: thread派生。改为创建一个成员变量:
class MyThread {
// ...
private:
// ...
boost::thread _thread;
};
在构造函数中,创建并为该成员变量分配一个线程:
MyThread() {
_thread = boost::thread(&MyThread::ThreadFunction,this);
}
并在析构函数中调用它的join()。
~MyThread() {
// ...
_thread.join();
}
那应该解决你的问题。
但是,如果您只想在销毁对象时退出线程(并且不必在其运行时将其唤醒),则可以使用其他方法。删除互斥锁和条件变量并改为使用中断。这将导致sleep()抛出异常,因此您必须捕获它:
void ThreadFunction() {
try {
for(;;) {
boost::this_thread::sleep(boost::posix_time::milliseconds(MAX_IDLE));
// Here goes some code executed by a thread
}
} catch( const boost::thread_interrupted& e ) {
// ignore exception: thread interrupted, exit function
}
}
当线程中断时,这将立即退出ThreadFunction。如果您不需要线程在每个周期休眠,则可以将其替换为boost::this_thread::interruption_point()
。如果线程被中断,这只会抛出异常。
现在你可以简单地在析构函数中断线程:
MyThread::~MyThread() {
_thread.interrupt();
_thread.join();
}