moveToThread位于QObject中,官方对此函数的解释如下:
void QObject::moveToThread(QThread *targetThread)
Changes the thread affinity for this object and its children. The object cannot be moved if it has a parent. Event processing will continue in the targetThread.
这个函数适合于QObject及其子类,并且QObject的父对象必须为空,否则移动到线程失败。移动成功后,将在目标线程中开启事件处理。
待移动到线程的Object
// 耗时操作具体执行的类 class Worker : public QObject { Q_OBJECT public: Worker(QObject* parent = 0); virtual ~Worker(); signals: void sglProgress(int val); // 进度信号,[0, 100],指示进度 void sglFinished(); // 结束信号 public slots: // 开始执行耗时操作的槽函数,结束后调用deleteLater(),析构自己 void start(); };
启动类
void FrmMain::sltWork() { Worker* worker = new Worker(0); // parent 需为0 // 连接耗时操作进度和完成信号对应的槽函数 connect(worker, SIGNAL(sglProgress(int)), this, SLOT(sltProgress(int))); connect(worker, SIGNAL(sglFinished()), this, SLOT(sltFinished())); QThread* thread = new QThread(0); // 开启一个新线程 worker->moveToThread(thread); // worker需在线程启动后开启,这也是耗时操作的start()函数是槽函数的原因 connect(thread, SIGNAL(started()), worker, SLOT(start())); // 耗时操作完成后,线程退出 connect(worker, SIGNAL(sglFinished()), thread, SLOT(quit())); // 特别说明(1),看后面详细说明 connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); // 启动线程 thread->start(); }
防止内存泄漏,需要使用deleteLater()函数析构thread,常见的一个bug是这样造成的
connect(worker, SIGNAL(sglFinished()), thread, SLOT(deleteLater()));
看上去好像也没什么,其实,会是一个很不稳定的因素,如果线程相对简单,可以很快quit掉,程序仿佛可以正常运行,而事实上并不总是这样,以为worker的sglFinished()信号同时连接了thread的quit()和deleteLater()两个槽函数,如果quit()还没执行完成时,就执行deleteLater(),会造成软件的崩,或者Destroyed while thread is still running这样的bug()。因此,sglFinished()信号连接了线程quit()函数,线程正常退出后,会释放finished()信号,然后由finished()信号连接线程的deleteLater()槽函数,会使线程安全的退出并析构。
参考:
1、Qt 多线程之QObject::moveToThread