线程的退出方式-QThread
-
QThread::terminate() - 不安全
官方说明:
终止线程的执行。线程可以立即终止,也可以不立即终止,这取决于操作系统的调度策略。请在terminate()之后使用QThread::wait()。
当线程终止时,所有等待该线程完成的线程将被唤醒。
警告:此函数是危险的,不鼓励使用。线程可以在其代码路径中的任何点终止。线程可以在修改数据时终止。线程没有机会自己清理,解锁任何持有的互斥锁等。简而言之,只有在绝对必要时才使用这个函数。
终止可以通过调用QThread::setTerminationEnabled()显式地启用或禁用。在终止被禁用时调用此函数将导致延迟终止,直到重新启用终止。有关更多信息,请参阅QThread::setTerminationEnabled()的文档。
我非常不建议大家使用这个函数,一旦使用这个函数,将会对我们的程序造成隐患,这在大型工程中是致命性的 -
QThread::exit(int returnCode = 0) - 正确使用才安全
官方说明:
用返回代码告诉线程的事件循环退出。
调用此函数后,线程离开事件循环并从QEventLoop::exec()调用中返回。函数的作用是:返回returnCode。
按照惯例,returnCode为0表示成功,任何非零值表示错误。
注意,与同名的C库函数不同,这个函数确实返回给调用者——停止的是事件处理。
在QThread::exec()被再次调用之前,QEventLoops将不会在这个线程中启动。如果QThread::exec()中的eventloop没有运行,那么下一次调用QThread::exec()也会立即返回 -
QThread::quit - 正确使用才安全
官方说明:
告诉线程的事件循环退出,返回代码为0(成功)。相当于调用QThread::exit(0)。
如果线程没有事件循环,则此函数不执行任何操作。
QThread安全退出:使用moveToThread的方式,在退出线程的时候,多数同学经常会碰到异常崩溃的情况,基本上都是报错 Destroyed while thread is still running ,说明线程还没有退出循环就被强制释放了资源,意思就是线程还在运行过程中被释放(delete)就造成了崩溃。所以我们在给线程发送退出指令之后,还要等待线程执行完此次事件循环,再才能delete掉这个thread指针。
例如使用了以下的代码( thread初始化方是 new QThread)释放资源
thread->quit();
delete thread;
或者使用了以下代码
thread->terminate();
delete thread;
这两段代码都是非常不安全的代码,不要使用。
安全的退出方式:使用QThread的finished信号绑定QObject的deleteLater函数实现资源自动释放,也可以绑定一个函数。退出时只需要调用quit()函数即可,如果绑定的是函数,则可以在适当的位置释放thread对象和Object对象。deleteLater函数可以查看Qt文档,这里就不做说明了
线程创建以及退出示例
- 创建
TestObject* object = new TestObject;
QThread* thread = new QThread;
object->moveToThread(thread );
connect(thread,&QThread::finished,object,&TestObject::deleteLater); // 退出后释放TestObject对象资源
connect(thread,&QThread::finished,thread,&QThread::deleteLater); // 退出后释放QThread对象资源
thread->start();
- 退出
thread->quit(); // 也可以使用thread->exit(0);
thread->wait(); // wait函数是个阻塞的接口,意思是线程必须真的退出了,才会执行wait之后的语句,否则将会一直阻塞在这里,如果在界面线程上使用,需要保证线程中代码的合理性。
thread = nullptr;
object = nullptr;
在适当的位置将 thread 和 object 置为nullptr,这样程序就安全了
线程的使用-moveToThread
moveToThread方法描述:
- 定义一个继承于QObject的worker类,在worker类中定义一个槽slot函数doWork(),这个函数中定义线程需要做的工作;
- 在要使用线程的Manager类中,新建一个QThread的对象和woker类对象,使用moveToThread()方法将worker对象的事件循环全部交由QThread对象处理;
- 建立相关的信号函数和槽函数进行连接,然后发出信号触发QThread的槽函数,使其执行工作。
举例如下:
头文件:
#include <QObject>
#include <QThread>
class Worker : public QObject
{
Q_OBJECT
public:
explicit Worker(QObject *parent = nullptr);
void doWork();
signals:
void signal_workerResult();
};
class Manager : public QObject
{
Q_OBJECT
public:
explicit Manager(QObject* parent = nullptr);
~Manager();
signals:
void signal_doWork();
private slots:
void slot_handleWorkerResult();
private:
QThread* workThread = nullptr;//工作线程
Worker* worker = nullptr;//工作任务
};
源文件:
#include "movetothread.h"
#include <QDebug>
#include <QTime>
#if defined(_MS