1. 概述

任何继承于QThread的线程都是通过继承 QThread 的run函数来实现多线程的,因此,必须重写QThread的run函数,把复杂逻辑写在QThread的run函数中。然后在主线程中调用 start() 函数来启动子线程。

2. UML 类的关系图

 
QT 中的多线程之继承 Thread-LMLPHP
 

3. 代码:

首先写 MyThread 类,该类继承于 QThread 类,该类中自定义了信号和槽,并且重写了 run 函数,头文件如下:

//
// MyThread.h
//
#ifndef DEL2_MYTHREAD_H
#define DEL2_MYTHREAD_H

#include <QThread>
#include <QDebug>

class MyThread : public QThread
{
Q_OBJECT

public:
    explicit MyThread(QObject* parent = nullptr);

signals:
    void myThreadSignal(const int);  // 自定义发送的信号

public slots:
    static void myThreadSlot(int);  // 自定义槽函数

protected:
    void run() override ;
};

#endif //DEL2_MYTHREAD_H

//
// mythread.cpp
//
#include "mythread.h"

MyThread::MyThread(QObject* parent)
    : QThread(parent)
{
}

//2. 新线程中的 0x4684
void MyThread::run()
{
    qDebug() << __FUNCTION__ << " Thread ID: " << QThread::currentThreadId() << "\n";

    emit myThreadSignal(100);  // 发送结束信号

    exec();
}

//3. 主线程中的  0x5120
void MyThread::myThreadSlot(const int val)
{
    qDebug() << __FUNCTION__ << " Thread ID: " << QThread::currentThreadId() <<  ", val: " << val <<"\n";
}

在 ThreadController 类中实现 MyThread 的调用

//
// threadcontroller.h
//
#ifndef THREADCONTROLLER_H
#define THREADCONTROLLER_H

#include <QObject>
#include "mythread.h"

class ThreadController : public QObject
{
Q_OBJECT

public:
    explicit ThreadController(QObject *parent = nullptr);

    ~ThreadController() override ;

public slots:
    static void handleResults(int result);  // 处理子线程执行的结果

signals:
    void operate(const int);  // 发送信号,触发线程

private:
    MyThread* _myThread ;

};

#endif // THREADCONTROLLER_H

//
// WorkerController.cpp
//
#include "threadcontroller.h"

ThreadController::ThreadController(QObject *parent) : QObject(parent)
{
    _myThread = new MyThread ;

    connect(_myThread, &MyThread::myThreadSignal, this, &ThreadController::handleResults);

    // 该线程结束时销毁
    connect(_myThread, &QThread::finished, this, &QObject::deleteLater);

    connect(this, &ThreadController::operate, _myThread, &MyThread::myThreadSlot);

    // 启动该线程
    _myThread->start();

    // 当前线程挂起 3s
    QThread::sleep(3);

    //3. --- 先执行当前槽函数,再执行run中槽函数
    emit operate(99);
}

ThreadController::~ThreadController()
{
    _myThread->quit();
    _myThread->wait();
}

//4. 主线程中的  0x5120
void ThreadController::handleResults(const int result)
{
    qDebug() << __FUNCTION__ << " Thread ID:" << QThread::currentThreadId() << ", last result: " << result;
}

接下来就是 main 函数,主函数中我们新建一个 Controller 对象,开始执行:

#include <QCoreApplication>
#include <QThread>
#include <QDebug>
#include "threadcontroller.h"


int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    qDebug() << __FUNCTION__ << " Thread ID:" << QThread::currentThreadId() << '\n' ;

    ThreadController c ;

    return a.exec(); // 进入事件循环
}


4. 运行结果及说明

QT 中的多线程之继承 Thread-LMLPHP

 
QT 中的多线程之继承 Thread-LMLPHP

注意:

  1. 只有 run() 中的才是新线程,其余都是主线程!
  2. QThread::sleep(3); 使用后,当前主线程挂起 3 秒,而子线程中 run() 继续执行,休眠结束后才会运行主线程的槽函数!

5. 结语

子类化 QThread 的方法,就是重写了 QThread 中的 run() 函数,在 run() 函数中定义需要的工作。这样的结果是,我们自定义的子线程调用 start() 函数后,便开始执行 run() 函数。如果在自定义的线程类 MyThread 中定义相关的槽函数,那么这些槽函数不会由子类化的QThread 自身事件循环所执行,而是由该子线程的拥有者(一般都是主线程)来执行。

而 qt 的线程设计不是希望通过继承去实现多线程,而是希望线程也是作为一个对象可以直接使用,也就是 QObject的moveToThread方法

本文也只是初步的学习,没有关注于线程的释放和创建,进一步使用可以参考: Qt使用多线程的一些心得

参考: QT 中的多线程—继承 QThread 篇

05-03 03:18