Qt QThread安全退出

13 篇文章 0 订阅

QThread的使用方式

在Qt中,使用QThread实现子线程的方式有两种:

  • 继承QThread,重写run函数
  • 继承QObject,使用moveToThread方式移动进QThread

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)。
    如果线程没有事件循环,则此函数不执行任何操作。

关于Qt事件循环的文章https://zhuanlan.zhihu.com/p/72758194

QThread安全退出

重写run函数的方式退出,这个我们好控制。但是使用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,这样程序就安全了

  • 21
    点赞
  • 156
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
在使用 QThread 时,如果需要立即终止线程,可以使用 QThread 中的 quit() 或 terminate() 方法。但是这些方法并不是安全的方法,因为它们会立即终止线程,而不会给线程任何机会来清理和释放资源,可能会导致一些问题,比如资源泄露等。因此,建议采用更安全的方式来终止线程。 一种更安全的方式是使用信号和槽机制。可以在线程中使用一个标志变量,在主线程中通过发送信号的方式将该标志变量设置为 true,然后在线程函数中定期检查该标志变量的值,如果发现该标志变量为 true,则安全退出线程。 下面是一个示例代码: ``` // MyThread.h class MyThread : public QThread { Q_OBJECT public: MyThread(QObject *parent = nullptr); void stop(); protected: void run() override; private: bool m_stopFlag; }; // MyThread.cpp MyThread::MyThread(QObject *parent) : QThread(parent), m_stopFlag(false) { } void MyThread::stop() { m_stopFlag = true; } void MyThread::run() { while (!m_stopFlag) { // do something } // clean up resources } // in main thread MyThread thread; thread.start(); // to stop the thread thread.stop(); thread.wait(); ``` 在上述代码中,MyThread 类继承自 QThread,通过添加一个 stop() 方法和一个标志变量 m_stopFlag,以及在 run() 方法中定期检查该标志变量的值,来实现安全的终止线程。在主线程中,可以调用 stop() 方法来设置标志变量为 true,然后调用 wait() 方法等待线程结束。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值