QT 中的多线程---moveToThread 篇

QThread 类提供了一个与平台无关的管理线程的方法。一个 QThread 对象管理一个线程。QThread 的执行从 run() 函数的执行开始,在 Qt 自带的 QThread 类中,run() 函数通过调用 exec() 函数来启动事件循环机制,并且在线程内部处理 Qt 的事件。在 Qt 中建立线程的主要目的就是为了用线程来处理那些耗时的后台操作,从而让主界面能及时响应用户的请求操作。QThread 的使用方法有如下两种:

  1. QObject::moveToThread()
  2. 继承 QThread 类

下面通过具体的方法描述和例子来介绍第一种方法,第二种方法在下一篇文章中介绍。

QObject::moveToThread() 方法

方法描述

  1. 定义一个继承于 QObject 的 worker 类,在 worker 类中定义一个槽函数 doWork(),这个函数中定义线程需要做的工作。
  2. 在要使用线程的 controller 类中,新建一个 QThread 的对象和 woker 类对象,使用 moveToThread() 方法将 worker 对象的事件循环全部交由 QThread 对象处理。
  3. 建立相关的信号函数和槽函数进行连接,然后发出信号触发 QThread 的槽函数,使其执行工作。
  4. 代码,首先新建一个 work 类,该类重点在于其 doWork 槽函数,这个函数定义了线程需要做的工作,需要向其发送信号来触发槽函数。
  5. //
    // Worker.h
    //
    
    #ifndef DEL_WORKER_H
    #define DEL_WORKER_H
    
    #include 
    #include 
    #include 
    
    class Worker : public QObject
    {
    Q_OBJECT
    
    public:
        explicit Worker(QObject *parent = nullptr);
    
    public slots:
        void doWork(int parameter);  // doWork 定义了线程要执行的操作
    
    signals:
        void resultReady(const int result);  // 线程完成工作时发送的信号
    };
    
    #endif //DEL_WORKER_H
    //
    // Worker.cpp
    //
    
    #include "Worker.h"
    
    Worker::Worker(QObject *parent)
    {
    
    }
    
    void Worker::doWork(int parameter)
    {
        qDebug() << "receive the execute signal" ;
        qDebug() << "\tCurrent thread ID: " << QThread::currentThreadId();
    
        // 循环一百万次
        for (int i = 0; i != 1000000; ++i)
        {
            ++parameter ;
        }
    
        // 发送结束信号
        qDebug() << "\tFinish the work and sent the result Ready signal\n" ;
    
        emit resultReady(parameter);
    }

    然后定义一个 Controller 类,这个类中定义了一个 QThread 对象,用于处理 worker 对象的事件循环工作。

  6. //
    // Controller.h
    //
    
    #ifndef DEL_CONTROLLER_H
    #define DEL_CONTROLLER_H
    
    #include 
    #include 
    #include 
    
    #include "Worker.h"
    
    // controller 用于 启动子线程 和 处理子线程执行的结果
    class Controller : public QObject
    {
    Q_OBJECT
    
        QThread workerThread ;
    
    public:
        explicit Controller(QObject *parent = nullptr);
    
        ~Controller() override ;
    
    public slots:
        static void handleResults(int result);  // 处理子线程执行的结果
    
    signals:
        void operate(const int);  // 发送信号,触发线程
    };
    
    #endif //DEL_CONTROLLER_H

    下面是 Controller 类的 cpp 文件,其构造函数中创建 worker 对象,并且将其事件循环全部交给 workerThread 对象来处理,最后启动该线程,然后触发其事件处理函数。

  7. //
    // Controller.cpp
    //
    
    #include "Controller.h"
    
    Controller::Controller(QObject *parent) : QObject(parent)
    {
        auto *worker = new Worker ;
    
        // 调用 moveToThread 将该任务交给 workThread
        worker->moveToThread(&workerThread);
    
        // operate 信号发射后启动线程工作
        connect(this, SIGNAL(operate(const int)), worker, SLOT(doWork(int)));
    
        // 该线程结束时销毁
        connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
    
        // 线程结束后发送信号,对结果进行处理
        connect(worker, SIGNAL(resultReady(int)), this, SLOT(handleResults(int)));
    
        // 启动线程
        workerThread.start();
    
        // 发射信号,开始执行
        qDebug() << "emit the signal to execute!" ;
        qDebug() << "\tCurrent thread ID:" << QThread::currentThreadId() << '\n' ;
    
        emit operate(0);
    }
    
    // 析构函数中调用 quit() 函数结束线程
    Controller::~Controller()
    {
        workerThread.quit();
        workerThread.wait();
    }
    
    void Controller::handleResults(const int result)
    {
        qDebug() << "receive the resultReady signal" ;
        qDebug() << "\tCurrent thread ID: " << QThread::currentThreadId() << '\n' ;
        qDebug() << "\tThe last result is: " << result ;
    }

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

  8. #include 
    #include 
    
    #include "Controller.h"
    
    int main(int argc, char *argv[])
    {
        qDebug() << "I am main Thread, my ID: " << QThread::currentThreadId() << "\n" ;
    
        QApplication a(argc, argv);
    
        Controller c ;
    
        return a.exec();
    }

    moveToThread 方法,是把我们需要的工作全部封装在一个类中,将每个任务定义为一个槽函数,再建立触发这些槽函数的信号,然后连接信号和槽,最后调用 moveToThread 方法将这个类交给一个 QThread 对象,再调用 QThread 的 start() 函数使其全权处理事件循环。于是,任何时候我们需要让子线程执行某个任务,只需要发出对应的信号就可以。

    其优点是我们可以在一个 worker 类中定义很多个需要做的工作,然后触发信号,子线程就可以执行。相比于继承 QThread 方法,只能执行 run() 函数中的任务,moveToThread 的方法中一个线程可以做很多不同的工作,只要实现对应的槽函数,触发对应的信号即可。

你可能感兴趣的:(QT,qt,开发语言)