Qt多线程编程-run()方法

本文介绍Qt多线程编程-run()方法。

Qt多线程编程主要有2种方法,前面已经介绍了moveToThread()方法,本文介绍另外一种方法run()方法,并给出一个实例参考。

1.基本原理

run()方法首先需要定义一个基于QThread的派生类,QThread类是用来创建和管理线程的类,它所依附的线程仍然在宿主线程(由parent指定),而它创建和管理的新线程即是run()启动的线程。也就是说基于QThread的派生类只有run函数是运行在新线程里的,这个类的其他所有函数都在这个类的宿主线程(由parent指定)中
因此,要启动一个新线程,需要重写这个基于QThread的派生类的run(),当run()结束之后,这个线程也就终结了。一般情况下,run()里面包含一个死循环,将耗时运算放在run(),在run()中将运算的结果通过信号发射出来,而在宿主线程与之绑定的槽函数中处理运算结果。

QThread常用的方法和信号:

1)线程的启动和退出

线程的启动可使用如下函数:

void QThread::start(QThread::Priority priority = InheritPriority)

线程的退出可使用如下函数:

void QThread::quit()

线程退出过程中需等待事件处理完毕,可使用如下函数:

bool QThread::wait(unsigned long time = ULONG_MAX)

2)线程完成信号

线程完成后,会发射如下信号:

void QThread::finished()

通常将线程完成信号和线程里的对象销毁连接。参考代码如下:

connect(worker, &Worker::finished, worker, &QObject::deleteLater);

2.实例

1)定义基于QThread的派生类

这里定义一个Worker类,这个类基于QThread,参考代码如下:

#ifndef WORKER_H
#define WORKER_H

#include <QObject>
#include <QThread>

class Worker : public QThread
{
    Q_OBJECT
public:
    explicit Worker(QObject *parent = nullptr);

public:
    void startWork();
    void stopWork();

protected:
    void run() override;

signals:
    void resultReady();

public slots:


private:
    bool bStarted;
};

#endif // WORKER_H

代码中重写了run()函数,并定义了一个signal将运算结果发射出来。

2)重写run()

run()函数一般是一个死循环,参考代码如下:

#include "worker.h"
#include <QDebug>


Worker::Worker(QObject *parent) : QThread(parent)
{
    bStarted = false;
}

void Worker::startWork()
{
    bStarted = true;
    qDebug() << "start work func thread ID:" << QThread::currentThreadId();
}

void Worker::stopWork()
{
    bStarted = true;
}

void Worker::run()
{
    qDebug() << "run func thread ID:" << QThread::currentThreadId();

    while (bStarted) {
        Q_EMIT resultReady();
        msleep(200);
    }

    quit();
}

这里为了方便展示run()所在的线程和Worker对象所在的线程,将它们的线程ID打印出来,同样,每隔200ms将运算结果发射出来。这里使用一个变量bStarted来退出线程。

3)宿主对象

宿主对象(这里的Controller对象)是位于主线程的,参考代码如下:

头文件:

#ifndef CONTROLLER_H
#define CONTROLLER_H

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


class Controller : public QObject
{
    Q_OBJECT
public:
    explicit Controller(QObject *parent = nullptr);
    ~Controller();

signals:

public slots:
    void handleResult();

private:
    Worker *worker;
};

#endif // CONTROLLER_H

源文件:

#include "controller.h"
#include <QDebug>

Controller::Controller(QObject *parent) : QObject(parent)
{
    worker = new Worker(this);

    connect(worker, &Worker::resultReady, this, &Controller::handleResult);
    connect(worker, &Worker::finished, worker, &QObject::deleteLater);
    worker->start();

    worker->startWork();
}

Controller::~Controller()
{
    if (worker->isRunning()) {
        worker->stopWork();
        worker->wait();
    }
}

void Controller::handleResult()
{
    qDebug() << "handle result";
}

这里,

a)在Controller类中,指定Worker的父对象指针为this,即指向Controller,换句话说就是Worker里的线程(run())依附于Controller。

b)将Worker类的resultReady()和槽函数handleResult()绑定在一起,为了演示,这里只是打印消息,模拟线程处理结果。

c)在Controller类的析构函数中,判断线程是否在运行,退出线程,并等待与之相关的事件处理完毕。

4)主函数

主函数实例化一个Controller对象,并打印其所在线程ID,参考代码如下:

#include <QCoreApplication>
#include "controller.h"
#include <QDebug>


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

    qDebug() << "main thread ID:" << QThread::currentThreadId();

    Controller controller;

    return a.exec();
}

5)运行结果

运行结果如下图:

从运行结果可以看出:

主函数的线程ID和Work对象里的非run()的线程ID是一样的,而run()里面的线程ID和主函数里的ID不同,验证了前面的说法。

3.与moveToThread()方法差异

moveToThread()方法适合事件驱动型的处理。比如串口读写,数据的到来是异步事件,为了防止数据丢失,需要一个独立的线程去读数据。整个数据处理过程:数据到来->产生readyRead信号->对应的槽函数处理。

run()方法适合固定周期轮询型的处理。比如嵌入式程序需要固定的采样周期通过I2C读取传感器数据或读取GPIO状态。这时用run()方法是比较合适的。

总结,本文介绍了Qt多线程编程-run()方法。

  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值