Qt多线程环境中应慎用while(true)循环和sleep()等待
在Qt实现多线程时,经常遇到需要需要在子线程中执行时长无限的耗时操作的情况,一种常见的实现是使用while (true) {}循环,并结合QThread::sleep()或QThread::usleep()实现等待,例如:
//Worker是继承自QObject的工作者对象,使用QObject::moveToThread()移动到子线程上 void Worker::InfinityJob() { while (bIsRunning) { //执行耗时操作和sleep()延时 //usleep(50); //允许子线程事件循环处理事件队列,并更新IsRunning变量 QApplication::processEvents(); } return; }
这种情况下,可能在运行中遇到意料之外的线程阻塞异常,甚至可能导致整个程序(包括主线程和子线程)进入休眠状态。这时,一个比较推荐的行为是使用QTimer::singleShot()函数,通过0毫秒的延时值模拟无限循环的行为。此时,需要将Worker::InfinityJob()定义为Worker类的槽函数(通过slot修饰)。
头文件Worker.h:
#ifndef WORKER_H #define WORKER_H #include <QObject> class Worker : public QObject { Q_OBJECT public: Worker(); ~Worker(); public slots: /* 这里放置各类槽函数的实现 */ void ExecuteWorkRequestedEventHandler(); void StopWorkRequestedEventHandler(); /* 具体的工作 */ void InfinityJob(); private: bool bIsRunning; //指示是否需要继续工作循环 }; #endif // WORKER_H
代码文件Worker.cpp:
#include "Worker.h" Worker::Worker() { bIsRunning = false; } Worker::~Worker() { bIsRunning = false; } void Worker::ExecuteWorkRequestedEventHandler() { bIsRunning = true; //开始执行InfinityJob() QTimer::singleShot(0, this, SLOT(InfinityJob())); return; } void Worker::StopWorkRequestedEventHandler() { bIsRunning = false; return; } void Worker::InfinityJob() { //执行耗时操作 //检查是否需要继续执行,并调用QTimer::singleShot()执行自身 if (bIsRunning) { QTimer::singleShot(0, this, SLOT(InfinityJob())); } return; }
参考资料:https://forum.qt.io/topic/98407/gui-freezes-even-with-multithreading/2
页面版本: 8, 最后编辑于: 05 May 2023 08:06