QThread的一种用法

目录

GUI线程不应该执行长时间的程序,以免界面卡死无法响应。耗时较长的程序可以在其他线程执行,并与GUI线程交互。Qt中界面应该只出现在主线程中,其他任务则可以放到子线程。

1. 我的方法
我在项目中使用QObject::moveToThread这种方式实现多线程,将多线程与应用逻辑区分开,无需继承QThread类,无需改写QThread::run方法,现有的逻辑代码可以很方便地使用进来(仅需继承QObject类,加入一些信号与槽)。项目中我参照网上的一篇博文:
[cpp]
void TaskManager::runTask()
{
SshTask* a_task = new SshTask(task_config);
a_task->moveToThread(&work_thread
);
connect(&work_thread_, SIGNAL(finished()), a_task, SLOT(deleteLater()));
connect(&work_thread_, SIGNAL(terminated()), a_task, SLOT(deleteLater()));
connect(&work_thread_,SIGNAL(started()),a_task,SLOT(runTask()));
work_thread_.start();
return;
}
[/cpp]
从文章开头提到的文档中可知,QObject::moveToThread方法中的QThread是持续运行的,任务对象执行完成时所在的工作线程不会停止。我将工作线程的start信号与任务相联系,仅在工作线程启动时执行程序。当再一次执行runTask方法时,工作进程没有停止,就无法用start信号执行下一次任务。对此,我在任务SshTask执行结束时终止线程运行,需要更多的信号与槽。修改版如下:
[cpp]
void TaskManager::runTask()
{
if(work_thread_.isRunning())
{
QMessageBox(QMessageBox::Critical,tr(“Run Task Failed”),tr(“Please wait for the current task to finish”)).exec();
return;
}
//…与上面相同…
// 验证
connect(a_task,SIGNAL(taskCompleteSuccessfulSignal(QString)),this,SLOT(verifySubmit(QString)));
connect(atask,SIGNAL(taskRunFailedSignal(TaskMessage)),this,SLOT(taskRunFailedSlot(TaskMessage)));
qDebug()<<“TaskManager: start the task”; work_thread_.start(); return; } void TaskManager::verifySubmit(const QString &task_std_out) { // … work_thread_.quit(); work_thread_.wait(); return; } void TaskManager::taskRunFailedSlot(const TaskMessage &task_message) { //… work_thread_.quit(); work_thread
.wait(); return; } [/cpp] 只允许一个任务运行,首先判断线程是否在运行,任务结束时强制终止线程。方法很繁琐,代码不优雅。

2. QThread文档中推荐的方法

Qt文档中对线程的详细介绍:《Threading Basics》。文中就是否使用多线程,以及何种方式实现多线程给出详细的介绍。
QThread文档中有此种方法的例子:
[cpp]
class Worker : public QObject
{
Q_OBJECT
QThread workerThread;
public slots:
void doWork(const QString &parameter) {
// …
emit resultReady(result);
}
signals:
void resultReady(const QString &result);
};
class Controller : public QObject
{
Q_OBJECT
QThread workerThread;
public:
Controller() {
Worker *worker = new Worker;
worker->moveToThread(&workerThread);
connect(workerThread, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(this, SIGNAL(operate(QString)), worker, SLOT(doWork(QString)));
connect(worker, SIGNAL(resultReady(QString)), this, SLOT(handleResults(QString)));
workerThread.start();
}
~Controller() {
workerThread.quit();
workerThread.wait();
}
public slots:
void handleResults(const QString &);
signals:
void operate(const QString &);
};
[/cpp]
QThread文档中给出的方法就没有上面的问题,任务Worker运行不受工作线程workerThread控制,由管理对象Controller的operate信号开启,这样就可以重复多次调用Worker任务。子线程在Controller生命周期内一直运行,但我还没用到项目中,不知道怎样才能保证只有一个任务运行,最近试一下能否同时进行多个任务。

参考

Threading Basics 
翻译版: Qt 线程基础(QThread、QtConcurrent等)