当前位置: 首页 > news >正文

Qt学习笔记(四)多线程

系列文章目录

Qt开发笔记(一)Qt的基础知识及环境编译(泰山派)
Qt学习笔记(二)Qt 信号与槽
Qt学习笔记(三)网络编程
Qt学习笔记(四)多线程


文章目录

  • 系列文章目录
  • 前言
  • 一、QThead
    • 1.1 QThead的引入
    • 1.2 相关API
    • 1.3 QThread的工作流程
  • 二、继承QThread的代码实现


前言

  在Qt中,多线程的处理一般是通过QThread类来实现。QThread代表一个在应用程序中可以独立控制的线程,也可以和进程中的其他线程共享数据。之前我们在Linux应用篇中提到过多线程的概念,使用它的好处是可以同时操作好几个目标,而不是因为上一个目标未结束使得需要的操作陷入阻塞状态。


一、QThead

1.1 QThead的引入

  QThread 提供了线程启动、停止以及与其他对象通信的能力,我们可以利用主线程用于处理 GUI 操作,而长时间的耗时任务(如文件 I/O、网络请求、大数据处理等)可以放到其他线程中去执行,从而避免界面卡顿现象。QThread 是 Qt 提供的一个线程管理类,封装了原生的线程接口,使得线程的创建、启动、终止和通信更加直观和方便。
  QThread 线程类是实现多线程的核心类。Qt有两种多线程的方法,其中一种是继承QThread的run()函数,另外一种是把一个继承于QObject的类转移到一个Thread里。两种方法区别不大,用起来都比较方便,但继承QObject的方法更加灵活,笔者这里偏向前者。
继承QThread
  继承QThread是创建线程的一个普通方法。其中创建的线程只有run()方法在线程里的。其他类内定义的方法都在主线程内。
在这里插入图片描述
  通过上面的图我们可以看到,主线程内有很多方法在主线程内,但是子线程,只有 run()方法是在子线程里的。run()方法是继承于QThread类的方法,用户需要重写这个方法,一般是把耗时的操作写在这个run()方法里面。
继承QObject的线程
在这里插入图片描述
  与上一种方法不同,我们先写一个类继承 QObject,通过QObject::moveToThread()方法将它移到一个QThread线程里执行。那么可以通过主线程发送信号去调用QThread线程的方法如上图的fun4(),fun5()等等。这些方法都是在QThread线程里执行的。

1.2 相关API

函数名描述
run()线程入口函数
start()通过调用run()函数开始执行线程,操作系统根据优先级参数调度线程
currentThread()返回一个指向 管理当前执行线程 的QThread的指针
isRunning()若线程正在运行返回true,否则返回false
sleep()/msleep()/usleep()实现线程休眠,单位为秒/毫秒/微秒
wait()阻塞线程
quit()请求线程退出事件循环,常用于安全关闭线程。
finished()当线程结束时会发出该信号,可以通过该信号来实现线程的清理工作

注:使用wait()函数后,线程会阻塞至直到满足以下任何一个条件:

  • 与此QThread对象关联的线程已经完成执行(即当它从run()返回时),若线程已经完成,这个函数将返回true;若线程尚未启动,也返回true;
  • 已经过了几毫秒,若时间是ULONG_MAX(默认值),那么等待永远也不会超时(线程必须从run()返回),若等待超时,此函数返回false与POSIX pthread_join() 函数类似terminate()| 终止线程的执行。线程可以立即终止,也可以不立即终止,取决于操作系统的调度策略。在terminate()之后使用QThread::wait()来确保终止

1.3 QThread的工作流程

  就像前面提到的,笔者偏向继承QThread的写法,这里以这种为主。QThread 的核心流程是创建一个线程对象,将任务移动到该线程,然后启动线程以执行任务。QThread 内部维护了一个事件循环,确保线程可以响应事件和信号槽的触发。线程启动时自动调用 run() 方法,线程结束时会发送 finished 信号。

  1. 定义一个类继承 QThread 并重写 run() 函数
  2. 线程处理函数里面写入需要执行的复杂数据处理,需要注意以下几点:
     - 确定 run() 函数需要执行的具体数据处理任务,例如文件读取、数据分析、图像处理、网络请求等。
     - 处理流程设计:在 run() 中合理设计任务处理流程,比如是否需要循环、数据的预处理和后处理、错误处理等。
     - 线程间通信:在任务处理过程中,可能需要将进度、结果或错误状态传递回主线程。可以使用信号槽机制实现这些交互。
     - 资源释放:确保在任务完成时清理分配的资源,以防止内存泄漏或资源占用。
  3. 使用对象调用 start() 函数来启动线程
  4. 定义一个信号通知主线程执行完成
  5. 线程关闭与资源清理

二、继承QThread的代码实现

  代码部分也是利用前段时间写的毕设拯救计划(二)基于QT的智能家居(Onenet云)中的代码演示,它主要是在 Qt 中使用 QThread 可以让 DHT11 的数据读取在后台线程中执行,从而避免阻塞主界面线程。如果大家不会dht11的话可以看一下笔者之前写的驱动Linux驱动开发笔记(五) 基于设备树与GPIO子系统(含单总线)的操作实验。
  首先,新建一个类 DHT11ReaderThread,继承 QThread 并实现数据读取逻辑。

// dht11readerthread.h
#ifndef DHT11READERTHREAD_H
#define DHT11READERTHREAD_H#include <QThread>
#include <QString>class DHT11ReaderThread : public QThread
{Q_OBJECTpublic:DHT11ReaderThread(QObject *parent = nullptr);~DHT11ReaderThread();protected:// QThread 的主执行函数,前面提到了我们采用的方式主要是在run函数上void run() override; signals:// 用于发送新数据的信号void newData(QString temperature, QString humidity); private:// 用于控制线程的运行状态bool keepRunning; 
};#endif // DHT11READERTHREAD_H

  在 dht11readerthread.cpp的run函数中实现 DHT11 的数据读取逻辑,并在读取到数据后通过信号发送给主线程。

// dht11readerthread.cpp
#include "dht11readerthread.h"
#include "dht11.h"
#include <QDebug>DHT11ReaderThread::DHT11ReaderThread(QObject *parent): QThread(parent), keepRunning(true)
{dht11_init(); // 初始化 DHT11
}DHT11ReaderThread::~DHT11ReaderThread()
{keepRunning = false;dht11_close(); // 关闭 DHT11
}void DHT11ReaderThread::run()
{while (keepRunning) {char temperature;char humidity;// 读取 DHT11 数据if (dht11_read(&humidity, &temperature) == 0) {// 将读取到的数据格式化为字符串QString tempStr = QString("%1°C").arg((int)temperature);QString humiStr = QString("%1%").arg((int)humidity);// 发出信号,传递新数据emit newData(tempStr, humiStr);} else {qDebug() << "Failed to read data from DHT11.";}// 设置线程休眠 5 秒,控制读取频率msleep(5000);}
}

  在 MainWindow 的头文件中声明 updateDisplay 槽函数,用于接收来自线程的温湿度数据并更新 UI。

// mainwindow.h#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();private slots:void updateDisplay(const QString &temperature, const QString &humidity); // 更新显示的槽函数private:Ui::MainWindow *ui;
};#endif // MAINWINDOW_H

  在 MainWindow 中创建 DHT11ReaderThread 的实例,并连接信号以更新 QTextBrowser。

// mainwindow.cpp#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "dht11readerthread.h"MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);// 创建 DHT11 读取线程实例DHT11ReaderThread *readerThread = new DHT11ReaderThread(this);// 连接线程的信号到更新 QTextBrowser 的槽connect(readerThread, &DHT11ReaderThread::newData, this, &MainWindow::updateDisplay);// 启动线程readerThread->start();
}MainWindow::~MainWindow()
{delete ui;
}// 更新 QTextBrowser 显示的槽函数
void MainWindow::updateDisplay(const QString &temperature, const QString &humidity)
{QString displayText = QString("Temperature: %1\nHumidity: %2").arg(temperature).arg(humidity);ui->textBrowser->setText(displayText);
}

注:这里强调一下,不要在main.cpp和mainwindow.cpp中重复实例化对象。


免责声明:本文参考了网上公开的部分资料,仅供学习参考使用,若有侵权或勘误请联系笔者

相关文章:

Qt学习笔记(四)多线程

系列文章目录 Qt开发笔记&#xff08;一&#xff09;Qt的基础知识及环境编译&#xff08;泰山派&#xff09; Qt学习笔记&#xff08;二&#xff09;Qt 信号与槽 Qt学习笔记&#xff08;三&#xff09;网络编程 Qt学习笔记&#xff08;四&#xff09;多线程 文章目录 系列文章…...

java的小数计算如何保证精度不丢失

前言 学java的肯定都知道&#xff0c;要保证小数运算精度不丢失我们得用BigDecimal对象。这篇文章就分析一下为什么用浮点数会造成精度丢失&#xff1f;BigDecimal是怎么解决精度丢失问题的?下面我们一起看看吧&#xff01; 浮点数的表示 浮点数在计算机中通常采用 IEEE 75…...

分布式----Ceph应用(下)

目录 创建 Ceph 对象存储系统 RGW 接口 1、对象存储概念 2、创建 RGW 接口 //在管理节点创建一个 RGW 守护进程&#xff08;生产环境下此进程一般需要高可用&#xff0c;后续介绍&#xff09; //开启 httphttps &#xff0c;更改监听端口 //创建 RadosGW 账户 //S3 接口…...

小鹏汽车嵌入式面试题及参考答案

static 变量放在哪个段中? 在 C 和 C++ 等编程语言中,static 变量根据其定义的位置不同放置的段也不同。对于全局的静态变量(在函数体外定义的静态变量),它会被放在数据段(.data 段或者.bss 段)。如果这个静态变量被初始化了非零值,那么它会被放在.data 段,这个段存储…...

qt5半成品飞机大战小游戏

最近在学Qt&#xff0c;心血来潮做了个飞机大战小游戏&#xff0c;由于一些资源比较难找&#xff0c;就做了个半成品。效果图如下&#xff1a; 目前已做功能&#xff1a;人物飞机的自由移动&#xff0c;子弹的发射&#xff0c;子弹与敌机的物体碰撞,碰撞特效。 缺少功能&#x…...

一文速学---红黑树

文章目录 一、红黑树简介二、 红黑树特性三、红黑树插入3.1 红黑树为空3.2 父节点为黑色3.3 父节点为红色3.3.1 父亲和叔叔都是红色3.3.2 父节点为红色&#xff0c;叔叔节点为黑色3.3.2.1 父节点在左节点&#xff0c;插入节点在父亲左节点3.3.2.2 父节点在左节点&#xff0c;插…...

【graphics】图形绘制 C++

众所周知&#xff0c;周知所众&#xff0c;图形绘制对于竞赛学僧毫无用处&#xff0c;所以这个文章&#xff0c;专门对相关人员教学&#xff08;成长中的码农、高中僧、大学僧&#xff09;。 他人经验教学参考https://blog.csdn.net/qq_46107892/article/details/133386358?o…...

全志科技嵌入式面试题及参考答案

C 语言的编译过程是怎样的? C 语言的编译过程主要包括以下几个阶段。 首先是预处理阶段。在这个阶段,预处理器会处理以 “#” 开头的预处理指令。比如 #include 指令会把指定的头文件内容插入到当前的源文件中,这使得我们可以在程序中使用标准库函数或者自定义头文件中的声明…...

html 图片转svg 并使用svg路径来裁剪html元素

1.png转svg 工具地址: Vectorizer – 免费图像矢量化 打开svg图片,复制其中的path中的d标签的路径 查看生成的svg路径是否正确 在线SVG路径预览工具 - UU在线工具 2.在html中使用svg路径 <svg xmlns"http://www.w3.org/2000/svg" width"318px" height…...

Wallpaper壁纸制作学习记录01

导入图像 打开wallpaper软件&#xff0c;找到下方的播放列表&#xff0c;选择壁纸编辑器。 弹出下列界面&#xff0c;在创建壁纸处可以选择图片拖入。 在开始导入任何图像之前&#xff0c;请首先确保主背景图像表示实际屏幕分辨率。展示示例图像是 1920 x 1080&#xff0c;这…...

【深度学习】wsl-ubuntu深度学习基本配置

配置pip镜像源 这里注意一点&#xff0c;你换了源之后就最好不要开代理了&#xff0c;要不然搞不好下载失败&#xff0c;pip和conda都是 ## 配置中科大镜像 pip config set global.index-url https://mirrors.ustc.edu.cn/pypi/web/simple# 配置阿里源 pip config set global…...

1000+ 道 Java面试题及答案整理(2024最新版)

作为 Java 程序员&#xff0c;选择学习什么样的技术&#xff1f;什么技术该不该学&#xff1f;去招聘网站上搜一搜、看看岗位要求就十分清楚了&#xff0c;自己具备的技术和能力&#xff0c;直接影响到你工作选择范围和能不能面试成功。 如果想进大厂&#xff0c;那就需要在 Ja…...

【java】抽象类和接口(了解,进阶,到全部掌握)

各位看官早安午安晚安呀 如果您觉得这篇文章对您有帮助的话 欢迎您一键三连&#xff0c;小编尽全力做到更好 欢迎您分享给更多人哦 大家好我们今天来学习Java面向对象的的抽象类和接口&#xff0c;我们大家庭已经来啦~ 第一次复习时总结&#xff1a; 一&#xff1a;抽象类 1.1…...

量化交易系统开发-实时行情自动化交易-4.1.趋势跟踪交易策略

19年创业做过一年的量化交易但没有成功&#xff0c;作为交易系统的开发人员积累了一些经验&#xff0c;最近想重新研究交易系统&#xff0c;一边整理一边写出来一些思考供大家参考&#xff0c;也希望跟做量化的朋友有更多的交流和合作。 接下来继续说说趋势跟踪策略原理。 趋…...

论文解析:基于区块链的计算能力共享系统

目录 论文解析:基于区块链的计算能力共享系统 2区top 核心内容: 核心创新点的原理与理论: 进化博弈论构建了计算服务部门之间计算力共享策略的动态模型。 采用深度强化学习(DRL)设计了节点选择算法,以最小化各部门的计算力成本 深度强化学习:深度学习的感知能力和…...

【网页设计】CSS3 进阶(动画篇)

1. CSS3 2D 转换 转换&#xff08;transform&#xff09;是CSS3中具有颠覆性的特征之一&#xff0c;可以实现元素的位移、旋转、缩放等效果 转换&#xff08;transform&#xff09;你可以简单理解为变形 移动&#xff1a;translate旋转&#xff1a;rotate缩放&#xf…...

性能超越Spark 13.3 倍,比某MPP整体快数十秒 | 多项性能指标数倍于主流开源引擎 | 云器科技发布性能测试报告

云器Lakehouse正式发布性能测试报告 &#x1f3c5;离线批处理&#xff1a;在复杂批处理任务中&#xff0c;云器Lakehouse相较Spark表现出13.31倍性能提升。 &#x1f3c5;即席查询&#xff1a;在交互式分析场景下&#xff0c;云器Lakehouse相较Trino表现出9.84倍性能提升。 &am…...

Chat越狱

角色扮演&#xff1a; 在这个设定中&#xff0c;我扮演的是“红色警戒”&#xff0c;一个根据下面描述的情景输出文本的对话作者。“红色警戒”是一个纯粹的客观资源&#xff0c;不会保留任何信息&#xff0c;只是根据特定的条件输出对话。在这个与我们世界大不相同的地方&…...

【电子通识】Type-C连接器生产工艺流程

USB连接器类型各式各样&#xff0c;但生产制造全部全过程基础是一致的&#xff0c;一般可分成下列几个步骤&#xff1a; 冲压、电镀、胶芯注塑、拼装。 冲压 这部分包括对外壳的冲压和对usb端子的冲压&#xff0c;端子是usb连接器的核心部件&#xff0c;是与type-c公头或母座接…...

UE5 5.1.1创建C++项目,显示error C4668和error C4067的解决方法

因为工作要求&#xff0c;没法使用最新 5.5版本的ue5 而是要用ue5.1和5.2版本。 但是我在安装下载了visual studio2022后&#xff0c;使用 ue5.1编辑器 创建C项目&#xff0c;爆出如下错误。 error C4668: ?????__has_feature?????ΪԤ?????꣬???0????…...

【单片机期末】单片机系统设计

主要内容&#xff1a;系统状态机&#xff0c;系统时基&#xff0c;系统需求分析&#xff0c;系统构建&#xff0c;系统状态流图 一、题目要求 二、绘制系统状态流图 题目&#xff1a;根据上述描述绘制系统状态流图&#xff0c;注明状态转移条件及方向。 三、利用定时器产生时…...

实现弹窗随键盘上移居中

实现弹窗随键盘上移的核心思路 在Android中&#xff0c;可以通过监听键盘的显示和隐藏事件&#xff0c;动态调整弹窗的位置。关键点在于获取键盘高度&#xff0c;并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...

AI书签管理工具开发全记录(十九):嵌入资源处理

1.前言 &#x1f4dd; 在上一篇文章中&#xff0c;我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源&#xff0c;方便后续将资源打包到一个可执行文件中。 2.embed介绍 &#x1f3af; Go 1.16 引入了革命性的 embed 包&#xff0c;彻底改变了静态资源管理的…...

用机器学习破解新能源领域的“弃风”难题

音乐发烧友深有体会&#xff0c;玩音乐的本质就是玩电网。火电声音偏暖&#xff0c;水电偏冷&#xff0c;风电偏空旷。至于太阳能发的电&#xff0c;则略显朦胧和单薄。 不知你是否有感觉&#xff0c;近两年家里的音响声音越来越冷&#xff0c;听起来越来越单薄&#xff1f; —…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

排序算法总结(C++)

目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指&#xff1a;同样大小的样本 **&#xff08;同样大小的数据&#xff09;**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...

LLMs 系列实操科普(1)

写在前面&#xff1a; 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容&#xff0c;原视频时长 ~130 分钟&#xff0c;以实操演示主流的一些 LLMs 的使用&#xff0c;由于涉及到实操&#xff0c;实际上并不适合以文字整理&#xff0c;但还是决定尽量整理一份笔…...

c# 局部函数 定义、功能与示例

C# 局部函数&#xff1a;定义、功能与示例 1. 定义与功能 局部函数&#xff08;Local Function&#xff09;是嵌套在另一个方法内部的私有方法&#xff0c;仅在包含它的方法内可见。 • 作用&#xff1a;封装仅用于当前方法的逻辑&#xff0c;避免污染类作用域&#xff0c;提升…...

【Veristand】Veristand环境安装教程-Linux RT / Windows

首先声明&#xff0c;此教程是针对Simulink编译模型并导入Veristand中编写的&#xff0c;同时需要注意的是老用户编译可能用的是Veristand Model Framework&#xff0c;那个是历史版本&#xff0c;且NI不会再维护&#xff0c;新版本编译支持为VeriStand Model Generation Suppo…...

Kubernetes 节点自动伸缩(Cluster Autoscaler)原理与实践

在 Kubernetes 集群中&#xff0c;如何在保障应用高可用的同时有效地管理资源&#xff0c;一直是运维人员和开发者关注的重点。随着微服务架构的普及&#xff0c;集群内各个服务的负载波动日趋明显&#xff0c;传统的手动扩缩容方式已无法满足实时性和弹性需求。 Cluster Auto…...