QThread 线程类是实现多线程的核心类。Qt 有两种多线程的方法,其中一种是继承 QThread
的 run()函数,另外一种是把一个继承于 QObject 的类转移到一个 Thread 里。
另外 Qt 提供了 QMutex、QMutexLocker、QReadLocker 和 QWriteLocker 等类用于线程之
间的同步,详细可以看 Qt 的帮助文档。
1、继承QThread的线程
主要使用run()方法,是继承于 QThread 类的方法,用户需要重写这个方法,一般是
把耗时的操作写在这个 run()方法里面。
例:
mainwindow.h文件代码如下:
cpp
/*新建一个类继承QThread*/
class WThread : public QThread
{
/* 用到信号槽即需要此宏定义 */
Q_OBJECT
public:
WThread(QWidget *parent = nullptr) {
Q_UNUSED(parent);
}
/* 重写 run 方法,继承 QThread 的类,只有 run 方法是在新的线程里 */
void run() override {
QString result = "线程开启成功";
/* 这里写上比较耗时的操作 */
// ...
// 延时 2s,把延时 2s 当作耗时操作
sleep(2);
/* 发送结果准备好的信号 */
emit resultReady(result);
}
}
在mainwindow.cpp中:
cpp
#include "mainwindow.h"
/*设置文本*/
....
MainWindow::~MainWindow()
{
/* 进程退出,注意本例 run()方法没写循环,此方法需要有循环才生效 */
workerThread->quit();
/* 阻塞等待 2000ms 检查一次进程是否已经退出 */
if (workerThread->wait(2000)) {
qDebug()<<"线程已经结束!"<<endl;
}
}
void MainWindow::handleResults(const QString &result)
{
/* 打印出线程发送过来的结果 */
qDebug()<<result<<endl;
}
void MainWindow::pushButtonClicked()
{
/* 检查线程是否在运行,如果没有则开始运行 */
if (!workerThread->isRunning())
workerThread->start();
}
2、继承QObiect的线程
继承 QObject 类更加灵活。它通过 QObject::moveToThread()方法,将一个 QObeject的类转移到一个线程里执行。
cpp
class Worker : public QObject
public slots:
/* 耗时的工作都放在槽函数下,工人可以有多份不同的工作,但是每次只能去做一份 */
void doWork1(const QString ¶meter) {
/* 标志位为真 */
isCanRun = true;
/* 死循环 */
while (1) {
/* 此{}作用是 QMutexLocker 与 lock 的作用范围,获取锁后,
/* 运行完成后即解锁 */
{
QMutexLocker locker(&lock);
/* 如果标志位不为真 */
if (!isCanRun) {
/* 跳出循环 */
break;
}
}
/* 使用 QThread 里的延时函数,当作一个普通延时 */
QThread::sleep(2);
emit resultReady(parameter + "doWork1 函数");
}
/* doWork1 运行完成,发送信号 */
emit resultReady("打断 doWork1 函数");
}
// void doWork2();...
public:
/* 打断线程(注意此方法不能放在槽函数下) */
void stopWork() {
qDebug()<<"打断线程"<<endl;
/* 获取锁后,运行完成后即解锁 */
QMutexLocker locker(&lock);
isCanRun = false;
}
signals:
/* 工人工作函数状态的信号 */
void resultReady(const QString &result);
};
不同于继承 QThread 类的线程 run(),继承 QThread 的类只有 run()在新线程里。而继承 QObject 的类,使用 moveToThread()可以把整个继承的 QObject 类移至线程里执行,所以可以有doWork1(),doWork2...等等耗时的操作,但是这些耗时的操作都应该作为槽函数,由主线程去调用。
mianwindow.cpp参考上面。
学习资料来源:正点原子视频