概述
Qt提供了一个管理线程的类:QThread。一个QThread对象管理一个线程。所以可以形象的把QThread当成一个线程去使用。
QThreads在run()中开始执行。默认情况下,run()通过调用exec()启动事件循环,并在线程内运行Qt事件循环。
您可以通过使用QObject::moveToThread()将工作者对象移动到线程中来使用它们。这种方法您可以自由地将Worker的slot连接到来自任何对象、任何线程的任何信号上。由于有一种称为QueuedConnections的机制,在不同线程之间连接信号和插槽是安全的。
另一种让代码在单独的线程中运行的方法是子类化QThread并重新实现run().
上述是官方的文档说明,也包含了案例,但是只是说了使用方法,没有说明在什么时候使用子类化QThread,什么时候使用QThread::moveToThread()。
但是我在使用的时候发现,不同的方法有不同的局限性。测试代码如下(存在界面文件,未贴出):
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QThread>
#include <QMutex>
#include <QMutexLocker>
#include <QDebug>
namespace Ui {
class MainWindow;
}
class TestThread;
class TestWork;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
signals:
void sig_test();
private slots:
void on_pushButton_clicked();
void on_pushButton_2_clicked();
private:
Ui::MainWindow *ui;
TestThread *test = Q_NULLPTR;
QThread workThread;
TestWork *worker = Q_NULLPTR;
};
class TestThread : public QThread
{
Q_OBJECT
public:
TestThread() {}
virtual ~TestThread() {}
void setStatus(bool s){
mutex.lock();
status = s;
mutex.unlock();
}
void run(){
int i = 0;
while (status) {
qDebug()<<"test 1:"<<i++;
sleep(1);
}
}
private:
bool status = true;
QMutex mutex;
};
class TestWork : public QObject
{
Q_OBJECT
public:
TestWork() {}
virtual ~TestWork() {}
void setStatus(bool s){
mutex.lock();
status = s;
mutex.unlock();
}
bool getStatus(){
return status;
}
void doWork(){
int i=0;
while (status) {
qDebug()<<"test 2:"<<i++;
QThread::sleep(1);
}
}
private:
bool status = false;
QMutex mutex;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
test = new TestThread();
// test->start();
worker = new TestWork;
//调用moveToThread将该任务交给workThread
worker->moveToThread(&workThread);
//信号触发
connect(this,&MainWindow::sig_test,worker,&TestWork::doWork);
//该线程结束时销毁
connect(&workThread, &QThread::finished, worker, &QObject::deleteLater);
//线程结束后发送信号,对结果进行处理
connect(worker, SIGNAL(resultReady(int)), this, SLOT(handleResults(int)));
//启动线程
workThread.start();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
if(test->isRunning()){
test->setStatus(false);
test->exit();
}else{
test->setStatus(true);
test->start();
}
}
void MainWindow::on_pushButton_2_clicked()
{
if(worker->getStatus()){
worker->setStatus(false);
}else {
worker->setStatus(true);
emit sig_test();
}
}
启动线程后,pushbutton_1的时候,run()是可以被控制的,可以一直连续的执行,可以正常调用该类的其他函数来控制run()中的循环条件。但是pushbutton_2的时候,如果doWork()执行了,也可以通过直接调用接口函数来控制doWork()中的循环条件。当存在多个需要控制的循环的时候,run()就无法适用,此时只需要加一个doWork2()函数即可实现相关需求。