现象
因项目需要,写了一个继承自QThread的线程类用于处理数据信息。
在给继承的线程类添加了父对象之后,程序可以正常执行,但是在关闭的时候报了如下的错误:
添加父对象的伪代码如下:
MyThread *pThread = new MyThread(this);
pThread->start();
原因分析
借着报错信息,提示了Destroyed while thread is still running,直译过来就是在线程仍然运行的情况下,把它摧毁了。
也就是说线程还在跑的情况下,执行了其析构函数。
鉴于此,测试了一些线程和其父对象的析构函数执行顺序,发现父对象的析构函数先被调用了,然后就报错。
这就得到了原因:
虽然给线程设置了父对象,理论上讲线程应该在父对象被析构之前调用,但是因为线程的特殊性,指向线程的指针变量优先被摧毁,但是线程本身的那块内存还在运行,这就导致了冲突。
解决方法
既然知道了原因,那么解决方法也就呼之欲出了 ———— 只需要在线程变量被摧毁之前,将线程停止即可。
这就设计两块内容:
1. 手动停止线程
2. 父对象等待线程停止
代码如下:
ParentObject::~ParentObject()
{
for (auto & thread: m_threads)
{
thread->stop(); // 自定义的线程停止函数
thread->wait(); // 主线程等待子线程停止
}
}
其中stop函数是自定义的线程停止函数,因为线程是一个死循环,因此给其设置了一个标志位——m_stop,停止的时候只需要将m_stop设为true即可。
void MyThread::stop()
{
m_stop = true;
}
当然,最好在线程的析构函数中添加另外的判断(习惯性,不添加也可):
MyThread::~MyThread()
{
if (this->isRunning())
{
this->stop();
}
}
设置完之后,程序正常退出,问题解决。