Qt 多线程使用moveToThread

文章介绍了如何使用QObject的moveToThread()方法将工作对象移动到新线程中执行任务。通过定义一个worker类,包含doWork()槽函数,在Controller类中创建线程并连接信号和槽,当发出信号时,worker对象在新线程中执行doWork()。这种方法允许在单个worker类中定义多个槽函数,执行不同任务,相比直接继承QThread更灵活。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

QObject::moveToThread() 方法

方法描述

  1. 定义一个继承于 QObject 的 worker 类,在 worker 类中定义一个槽函数 doWork(),这个函数中定义线程需要做的工作。 
  2. 在要使用线程的 controller 类中,新建一个 QThread 的对象和 woker 类对象,使用 moveToThread() 方法将 worker 对象的事件循环全部交由 QThread 对象处理。 
  3. 建立相关的信号函数和槽函数进行连接,然后发出信号触发 QThread 的槽函数,使其执行工作。

代码

首先新建一个 work 类,该类重点在于其 doWork 槽函数,这个函数定义了线程需要做的工作,需要向其发送信号来触发槽函数。

//
// Worker.h
//

#ifndef DEL_WORKER_H
#define DEL_WORKER_H

#include <QObject>
#include <QDebug>
#include <QThread>

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 对象的事件循环工作。

//
// Controller.h
//

#ifndef DEL_CONTROLLER_H
#define DEL_CONTROLLER_H

#include <QObject>
#include <QThread>
#include <QDebug>

#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 对象来处理,最后启动该线程,然后触发其事件处理函数。

//
// 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 对象,开始执行:

#include <QApplication>
#include <QThread>

#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();
}

运行结果及说明

main 函数中打印当前线程编号,即主线程的线程编号是 0x7f4078b2b740,在 Controller 的构造函数中继续打印当前线程编号,也是主线程编号,之后把 work 类的工作交给子线程后,给子线程发送信号,子线程收到了信号开始执行,其线程号为0x7f404fd3c700,执行结束后发送信号给 Controller 处理结果。


结语

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

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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值