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

news2024/11/28 20:34:14

本文介绍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()方法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2034634.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

cAdvisor+prometheus+grafana搭建监控页面并嵌入自定义页面中

三者关系 一般公司会有很多docker主机&#xff0c;那么就需要对docker进行监控了&#xff0c;docker监控可以采用docker stats配合shell命令来取值做监控&#xff0c;但是无法传递给prometheus进行采集&#xff0c;zabbix监控docker又比较麻烦&#xff0c;因此就有了谷歌的cad…

Python开源项目周排行 2024年第13周

#2024年第13周2024年8月5日1roop一款基于深度学习框架TensorFlow和Keras开发的单图换脸工具包&#xff0c;提供了丰富的功能和简洁易用的界面&#xff0c;使得用户可以轻松实现单图换脸操作。支持多张人脸替换成同一个人脸&#xff0c;勾选多人脸模式即可 人脸替换 高清修复自…

RCE绕过方式

目录 小于8个字符突破限制 无字母数字执行 php7的做法 php5的思考 PHP5shell 深入理解glob通配符 构造POC&#xff0c;执行任意命令 无参数读文件和RCE总结 代码解读 构造. 另一种构造方法 小于8个字符突破限制 但也只能执行一些非常短的命令&#xff0c;没有什么意义…

【JavaSec】 代码审计01-SpringMVC图书购物系统

【JavaSec】 代码审计01-SpringMVC图书购物系统 文章目录 【JavaSec】 代码审计01-SpringMVC图书购物系统前期部署用户管理修改删除 商品管理修改 普通用户注册 源码地址&#xff1a;https://github.com/Laverrr/bookstore 前期部署 问题一&#xff1a; 启动后报错 Cookie值…

RabbitMQ应用问题 - 消息顺序性保证、消息积压问题

文章目录 MQ 消息顺序性保证概述原因分析解决方案基于 spring-cloud-stream 实现分区消费 消息挤压问题概述原因分析解决方案 MQ 消息顺序性保证 概述 a&#xff09;消息顺序性&#xff1a;消费者消费的消息的顺序 和 生产者发送消息的顺序是一致的. 例如 生产者 发送消息顺序…

centos7 xtrabackup mysql(8)压缩 增量备份(3)

centos7 xtrabackup mysql&#xff08;8&#xff09;压缩 增量备份&#xff08;3&#xff09; 添加数据1 添加数据测试一下 测试主从是否可以 主机端 mysql -u root -p 1234aA~1 show databases ; use company_pro; show tables ; insert into employee(name) value (‘2024…

C++实现单例模式/工厂模式

单例模式 单例模式即一个类只创建一个实例&#xff0c;提供一个全局访问点。单例模式主要是为了控制资源访问&#xff0c;在一些功能如&#xff1a;数据库连接池&#xff0c;日志类实例&#xff0c;线程池等都可以采用单例模式。 // 实现一个单例 #include<iostream> #…

户外上网黑科技|续航能力大比拼,飞猫、闪鱼、格行、品胜,哪个好

在当今的移动互联网时代&#xff0c;随身WiFi已成为我们日常生活中不可或缺的一部分&#xff0c;特别是在租房、出差、旅行或户外活动时&#xff0c;其续航能力成为了用户选择的重要因素。本文将针对飞猫、闪鱼、格行、品胜这四款热门随身WiFi产品的续航能力进行详细比较&#…

C#高级:在SQLserver中使用视图、存储过程、索引和触发器

目录 一、视图 1.视图是什么&#xff0c;有什么作用&#xff1f; 2.视图和存储过程有什么区别&#xff1f; 3.建立一个视图&#xff0c;名为PersonBorrowView&#xff0c;SQL已给出&#xff1a; 4.如果往BorrowInfo加一条记录&#xff0c;我原本的SQL会增加一条记录&#…

JAVA毕业设计635—基于Java+ssm的仓库管理系统(源代码+数据库)

毕设所有选题&#xff1a; https://blog.csdn.net/2303_76227485/article/details/131104075 基于Javassm的仓库管理系统(源代码数据库)635 一、系统介绍 分为员工、管理员两种角色 1、员工&#xff1a; 登录、库存管理、出入库管理、密码修改 2、管理员&#xff1a; 库…

(自用)交互协议设计——protobuf序列化

protobuf是一种比json和xml等序列化工具更加轻量和高效的结构化数据存储格式&#xff0c;性能比json和xml真的强很多&#xff0c;毕竟google出品。 protobuf原理 protobuf如何使用 创建xxx.proto文件 开头写上 syntax"proto2"package tutorial; 表明使用的proto…

Linux:修改网卡名称(redhat-centos-redora)

解决问题: 我现在有块网卡名ens160&#xff0c;我想把他改为ens33&#xff08;仅是模拟&#xff0c;实际中你可以任意更改&#xff0c;不是局限在这两名称中&#xff0c;举一反三&#xff09; 我当前的操作系统为&#xff1a;centos9 解决办法&#xff1a; 1.修改grub配置 …

前端学习笔记-JS篇-02

运算符 赋值运算符 对变量进行赋值的运算符。 已经学过的赋值运算符:【将等号右边的值赋予给左边&#xff0c;要求左边必须是一个容器】 其他赋值运算符: - * / % 原始写法和简化写法【其实就是java基础】 一元运算符 众多的JavaScript 的运…

免费【2024】springboot 个人健康管理网站的设计与实现

博主介绍&#xff1a;✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌ 技术范围&#xff1a;SpringBoot、Vue、SSM、HTML、Jsp、PHP、Nodejs、Python、爬虫、数据可视化…

php 企业员工考勤系统—计算机毕业设计源码17108

摘要 由于数据库和数据仓库技术的快速发展&#xff0c;企业员工考勤系统建设越来越向模块化、智能化、自我服务和管理科学化的方向发展。员工管理系统对处理对象和服务对象&#xff0c;自身的系统结构&#xff0c;处理能力&#xff0c;都将适应技术发展的要求发生重大的变化。 …

Linux系统安全及应用(二):PAM安全认证

文章目录 4Linux中的PAM安全认证介绍su命令的安全隐患PAM认证原理和构成PAM安全认证流程PAM 配置文件结构说明PAM 控制标记的补充说明PAM 实例 4Linux中的PAM安全认证 介绍 PAM&#xff08;Pluggable Authentication Modules&#xff09;&#xff0c;可插拔式认证模块是一种高…

高翔【自动驾驶与机器人中的SLAM技术】学习笔记(七)卡尔曼滤波器三:卡尔曼滤波器公式推导【转载】

卡尔曼滤波器三&#xff1a;卡尔曼公式推导 转载来源&#xff1a;卡尔曼滤波&#xff1a;从入门到精通 简述 考虑一个SLAM 问题&#xff0c;它由一个运动方程&#xff1a; x t f ( x t − 1 , u t ) ω t (1) \mathbf{x}_{t}f(\mathbf{x}_{t-1},\mathbf{u}_{t}) \omega_…

尚品汇-ES(三十一)

目录&#xff1a; &#xff08;1&#xff09;封装搜索相关实体对象 &#xff08;2&#xff09;搜索接口封装 &#xff08;3&#xff09;在service-list-client模块添加远程接口 &#xff08;1&#xff09;封装搜索相关实体对象 搜索参数实体&#xff1a;SearchParam 搜索参…

haproxy高级功能配置

介绍HAProxy高级配置及实用案例 一.基于cookie会话保持 cookie value:为当前server指定cookie值&#xff0c;实现基于cookie的会话黏性&#xff0c;相对于基于 source 地址hash 调度算法对客户端的粒度更精准&#xff0c;但同时也加大了haproxy负载&#xff0c;目前此模式使用…

Service服务在Android中的使用

目录 一&#xff0c;Service简介 二&#xff0c;Service的两种启动方式 1&#xff0c;非绑定式启动Service 2&#xff0c;绑定式启动Service 三&#xff0c;Service的生命周期 1&#xff0c;非绑定式Service的生命周期 2&#xff0c;绑定式Service的生命周期 四&#xf…