【Qt】QThread moveTothread-多线程的两种实现方法

一、如何理解多线程
二、实现多线程的两种方式(面向应用)
2.1 继承 QThread 的类
2.2 (推荐这种方式)函数 moveTothread()
三、多线程的释放问题(善后工作)

多线程的两种实现方法

  • 一、如何理解多线程
  • 二、实现多线程的两种方式(面向应用)
    • 2.1 继承 QThread 的类
    • 2.2 (推荐这种方式)函数 moveTothread()
  • 三、多线程的释放问题(善后工作)

一、如何理解多线程

类似我们单片机的编程,如在 Keil5 中对 51 单片机或者 STM32 单片机进行编程时,如果我们使用模块化编程,那么 main.c文件中可能代码如下:

#include "stm32f103c8t6.h"void main(){//初始化配置函数while(1){//控制函数,如点灯?}
}

从代码块中可以看出,我们写了一个 while 循环,目的是为了让程序一直运行,而如果去掉 while 循环,只点灯,可能灯就只会亮 1 下(可能人眼都看不到这一下)。而我们还会用到中断,中断就是打断主程序运行,去处理一下突然的内容(比如说外卖员给你打电话了,虽然你现在正在写代码,但是你接到了这个电话就去拿外卖了)
但是对于现在的电脑来说,中断是一种穿插执行任务的方式,多线程也是,这个可以理解为,我一边看动漫一边写代码,同时处理 2 件或以上的事情。

总结:多线程就是使程序能够同时处理多个任务
主线程:理解为窗口线程UI 线程默认线程,负责窗口事件处理或者窗口控件数据的更新
子线程:负责后台处理一些内容,不能对窗口对象做任何操作,这些事情需要交给窗口线程处理,如果主线程需要与子线程进行信息的交互,需要用到 Qt 中的信号槽机制(子线程将信号发给主线程,然后主线程再进行调用)。
应用:当程序在处理一个内容时,用多余的资源处理其他力所能及的事
对串口调试助手来说,若要开启多个串口,哪就是创建多个串口对象,然后同时运行即可?(2024年1月5日试一下)

二、实现多线程的两种方式(面向应用)

QThread的两种实现.zip(学习测试 moveTothread 和基础 QThread 两种方法,第一次写)
TreadMethod.zip(这篇博客的完整代码)

2.1 继承 QThread 的类

继承 QThread 的方式实现多线程,实际上这是一种理解上简单,但是在实际应用中稍显复杂,并且程序越复杂,这个方法越笨拙不灵活。(在看教程的时候看到网上的人说,如果要实现网络 TCP 调试助手的话,非常不建议用继承 QThread 的类的方式来实现多线程)
这种方法,实际上是继承 QThread 的类,然后通过通过重写 run 函数来实现多线程。接下来做一个小栗子:
实例要求:打印三个线程 ID,包括主线程(UI 线程)ID、子线程 run 函数线程ID、子线程槽函数线程ID
细节:程序运行时先打印子线程 ID 和主线程 ID,然后通过发出信号,触发子线程槽函数线程 ID。
Step1:新建一个类 thread_1,选择继承 QObject,然后改成继承 QThread 的类
recording.gif
Step2:重写 run 方法
Step3:写一个子线程的槽函数

#ifndef THREAD_1_H
#define THREAD_1_H
#include <QThread>
#include <QDebug>
class thread_1 : public QThread
{
Q_OBJECT
public:
explicit thread_1(QThread *parent = nullptr);
signals:
protected:
void run() override{qDebug()<<"子线程ID:" <<QThread::currentThreadId()<<'\n';sleep(5);
};
public slots:
void thread1Slot(){qDebug()<<"子线程槽函数ID:" <<QThread::currentThreadId()<<'\n';
}
};
#endif // THREAD_1_H

step4:在 UI 线程中打印线程 ID 和新建线程和初始化运行
step5:链接(主线程)信号和(子线程)信号槽,并发射信号触发子线程信号槽打印其目前的线程ID

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include "thread_1.h"
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();private:Ui::MainWindow *ui;thread_1* myThread;
signals:void mainwindownSignal();};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);//新建一个子线程对象并让他开始运行myThread = new thread_1;myThread->start();//开始运行后会执行run函数,打印子线程的ID//执行打印主函数线程IDqDebug()<<"主线程ID:" <<QThread::currentThreadId()<<'\n';//链接(主线程)信号和(子线程)信号槽,并发射信号触发子线程信号槽打印其目前的线程IDconnect(this,&MainWindow::mainwindownSignal,myThread,&thread_1::thread1Slot);emit mainwindownSignal();
}

结果展示
① 结果让我有些意外,明明是让子线程先运行的,但是最先运行的是主线程,然后其次是子线程的槽函数,最后才是子线程的运行。
② 另外从图中可以看到,子线程的槽函数竟然处于主线程中!
image.png

2.2 (推荐这种方式)函数 moveTothread()

创建一个继承 QObject 的类(必须是继承 QObject),然后调用 moveTothread 方法,将这个继承 QObject 类的对象放到某个线程中,这样的好处是,可以让好几个对象放在同一个子线程中,而用方法一每次只能一个类来跑单一的线程,而且只能在 run 里跑,他子线程的槽函数还是运行在主线程中,想要实现多个线程就得继承多个 QThread 对象。
接下来做一个小栗子:
实例要求:打印三个线程 ID,包括主线程(UI 线程)ID、子线程 run 函数线程ID、子线程槽函数线程ID
细节:程序运行时先打印子线程 ID 和主线程 ID,然后通过发出信号,触发子线程槽函数线程 ID。
step1:创建一个继承 QObject 的类 work(与方法一类似,不展示了,为什么叫 work?我觉得因为这是一个要做的事所以叫他 work
step2:在这个类中写普通方法和槽函数

#ifndef WORK_H
#define WORK_H
#include <QObject>
#include <QDebug>
#include <QThread>
class work : public QObject
{Q_OBJECT
public:explicit work(QObject *parent = nullptr);void Working(){//写普通方法qDebug()<<"子线程ID:" <<QThread::currentThreadId()<<'\n';}
signals:
public slots:void WorkingSlot(){//写槽函数qDebug()<<"子线程ID:" <<QThread::currentThreadId()<<'\n';}
};
#endif // WORK_H

step3:在 mainwindow.h 中创建 workQThread 的对象:workermyThread
step4:在 mainwindow.h 中写触发 worker 槽函数的信号mainwindownSignal

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include "work.h"
#include <QDebug>
#include <QThread>QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();private:
//step3:在 mainwindow.h 中创建 work 和 QThread 的对象:worker 和myThreadUi::MainWindow *ui;work* worker;QThread* myThread;
signals:
//step4:在 mainwindow.h 中写触发 worker 槽函数的信号mainwindownSignalvoid mainwindownSignal();
};
#endif // MAINWINDOW_H

step5:在 mainwindow.c 中进行 moveTothread、start 以及信号槽的连接触发操作

#include "mainwindow.h"
#include "ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);worker = new work;myThread = new QThread;worker->moveToThread(myThread);//moveTothreadmyThread->start();//也要start才能运行//worker->Working();//让工人工作!看看是不是在子线程中处理!connect(this,&MainWindow::mainwindownSignal,worker,&work::WorkingSlot);connect(this,&MainWindow::mainwindownSignal,worker,&work::Working);emit mainwindownSignal();//发出信号,让worker中的槽函数开始执行看看是在哪个线程中执行qDebug()<<"主线程ID:" <<QThread::currentThreadId()<<'\n';
}MainWindow::~MainWindow()
{delete ui;
}

结果展示
① 通过信号的方式触发操作子线程让其运行是在子线程中运行的。(但是如果直接调用 working 方法,还是在主线程中,L13 去掉注释看看)
image.png

三、多线程的释放问题(善后工作)

QThread 对象不能挂载在对象树上进行自动释放,会出问题,手动释放比较好。
第二部分介绍了怎么实现,但是对于多线程的资源释放,这里也简单总结一下,原理我也不是很擅长说。

当子线程运行结束后,退出线程并回收线程空间

connect(mComThread,&QThread::finished, this,&QObject::deleteLater);


参考教程:
Qt 教程-爱编程的大丙
Qt 串口多线程 继承QThread_pyqt串口多线程-CSDN博客
QThread的用法-CSDN博客

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

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

相关文章

跟着暄桐林曦老师读《宝贵的人生建议》,重视心这颗种子

暄桐林曦老师在《见道明心的笔墨》读书课上讲到&#xff1a;人要在心这颗种子上去进化。当人的动机和果实都清静时&#xff0c;才能在内心具足里转化出更多可能性&#xff0c;进入正面的循环里。“宽以待人&#xff0c;严以律己&#xff0c;反之&#xff0c;则人人身处地狱”&a…

贯穿设计模式-装饰者模式

样例代码 涉及到的项目样例代码均可以从https://github.com/WeiXiao-Hyy/Design-Patterns.git获取 需求 旨在不改变一个对象逻辑的前提下&#xff0c;为这个对象添加其他额外的职责 在业务投放的同时&#xff0c;需要给用户发放红包或者积分&#xff0c;在不改动的投放逻辑的前…

golang实现rpc方法二:使用jsonrpc库【跨平台】

首先在golang实现rpc方法一net/rpc库中实现了RPC方法&#xff0c;但是那个方法不是跨平台的&#xff0c;没法在其他语言中调用这个实现的RPC方法&#xff0c;接下来我们可以通过jsonroc库实现跨语言的RPC方法。俩种实现方式的代码其实也是差不多的&#xff0c;大差不差&#xf…

仿stackoverflow名片与b站名片实现(HTML、CSS)

目录 前言一、仿stackoverflow名片HTMLCSS 二、仿b站名片HTMLCSS 素材 前言 学习自ACwing - Web应用课 一、仿stackoverflow名片 HTML <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport&…

BDD(Behavior-Driven Development)行为驱动开发介绍

为什么需要BDD&#xff1f; “开发软件系统最困难的部分就是准确说明开发什么” (“The hardest single part of building a software system is deciding precisely what to build” — No Silver Bullet, Fred Brooks) 。 看一下下面的开发场景&#xff1a; 场景一&#xf…

基于TCP的全双工网络编程实践

首先我们先了解一下什么是全双工通信&#xff1f; 全双工数据通信允许数据同时在两个方向上传输&#xff0c;因此&#xff0c;全双工通信相当于是两个单工通信方式的结合&#xff0c;它要求发送设备和接收设备都有独立的接收和发送能力。 TCP服务端代码&#xff1a; #includ…

M-VAE

Word2Vec c(y) 辅助信息 作者未提供代码

音频和视频基础知识

声音 什么是声音&#xff1a; 声音是由物体振动产生的&#xff0c;物体发生振动&#xff0c;对周围的空气产生挤压&#xff0c;从而产生声音。声音是一种压力波&#xff0c;使周围的空气产生疏密变化&#xff0c;形成疏密相间的纵波&#xff0c;由此产生了声波。 声波三要素&…

HUAWEI华为MateStation S台式机电脑12代PUC-H7621N,H5621N原装出厂Windows11.22H2系统

链接&#xff1a;https://pan.baidu.com/s/1QtjLyGTwMZgYiBO5bUVPYg?pwd8mx0 提取码&#xff1a;8mx0 原厂WIN11系统自带所有驱动、出厂主题壁纸、系统属性专属联机支持标志、Office办公软件、华为电脑管家等预装程序 文件格式&#xff1a;esd/wim/swm 安装方式&#xf…

dbeaver连接人大金仓报错 can‘t load driver class ‘com.kingbase8.Driver;‘

dbeaver可以连接很多数据库&#xff0c;设置dbeaver连接人大金仓&#xff0c;下载安装完成后&#xff0c;需要自行配置人大金仓的驱动&#xff0c;否则无法连接数据库。 一、dbeaver 下载 dbeaver 下载地址&#xff1a;https://dbeaver.io/download/ 二、查找人大金仓驱动 首…

[含完整代码]Linux使用.sh脚本自动部署(启动|停止|状态|日志)项目[超详细]

前言&#xff1a; 个人博客&#xff1a;www.wdcdbd.com 我们在linux部署.jar项目时&#xff0c;都需要通过java -jar的形式来部署&#xff0c;每次都要手动停止&#xff0c;部署&#xff0c;这样用起来会很麻烦。所以&#xff0c;这篇文章就是自己通过.sh脚本一键启动&#xf…

XCTF:hello_pwn[WriteUP]

使用checksec查看ELF文件信息 checksec 4f2f44c9471d4dc2b59768779e378282 这里只需要注意两个重点&#xff1a; Arch&#xff1a;64bit的文件&#xff0c;后面写exp的重点 Stack&#xff1a;No canary found 没有栈溢出保护 使用IDA对ELF文件进行反汇编 双击左侧的函数栏…

陶瓷碗口缺口检测-图像分割

图像分割 由于对碗口进行缺口检测&#xff0c;因此只需要碗口的边界信息。得到陶瓷碗区域填充后的图像&#xff0c;对图像进行边缘检测。这是属于图像分割中的内容&#xff0c;在图像的边缘中&#xff0c;可以利用导数算子对数字图像求差分&#xff0c;将边缘提取出来。 本案…

test-04-test case generate 测试用例生成 tcases A model-based test case generator

拓展阅读 junit5 系列 基于 junit5 实现 junitperf 源码分析 Auto generate mock data for java test.(便于 Java 测试自动生成对象信息) Junit performance rely on junit5 and jdk8.(java 性能测试框架。性能测试。压测。测试报告生成。) 自动生成测试用例 Tcases&#xf…

查看lucene和elasticsearch的版本对应关系

一、Maven仓库官网&#xff1a; https://mvnrepository.com/ 二、搜索elasticsearch&#xff0c;然后点击Server或者elasticsearch进入。 三、点击相应的版本号进入。 四、查看对应的lucene版本。 END

SwiftUI CoreData Picker

开发多账本功能 CoreData 与 Picker 的使用 上代码&#xff1a; // // TestZhangBenPicker.swift // pandabill // // Created by 朱洪苇 on 2024/1/14. //import SwiftUIstruct TestZhangBenPicker: View {FetchRequest(sortDescriptors: [SortDescriptor(\.cc_at)],anima…

VMware迁移虚拟机教程,适用于换电脑、重装系统

新购入了一台电脑&#xff0c;接下来可能会有连续好多篇与装机/重装系统/装软件有关的文章&#xff0c;平时可能只是纸上谈兵&#xff0c;这次是花重金买素材了&#xff0c;建议收藏 问题背景&#xff1a;在之前的电脑上&#xff0c;安装了VMware Workstation&#xff0c;并配…

第三十九周:文献阅读+Transformer

目录 摘要 Abstract 文献阅读&#xff1a;CNN与LSTM在水质预测中的应用 现有问题 提出方法 相关模型 CNN LSTM CNN-LSTM神经网络模型 模型框架 CNN-LSTM神经网络 研究实验 数据集 模型评估指标 数据预处理 实验设计与结果 研究贡献 Transformer Encoder-Dec…

C#灵活的任务调度组件FluentScheduler

FluentScheduler是一个C#的灵活的任务调度组件&#xff0c;支持各类任务调度。网上有很多演示代码&#xff0c;此处记录下来&#xff0c;方便自己查找。 // See https://aka.ms/new-console-template for more information //Console.WriteLine("Hello, World!");us…

prometheus常用exporter

一、node-exporter node_exporter&#xff1a;用于监控Linux系统的指标采集器。 未在k8s集群内的linux机器监控 GitHub - prometheus/node_exporter: Exporter for machine metrics 常用指标&#xff1a; •CPU • 内存 • 硬盘 • 网络流量 • 文件描述符 • 系统负载 •…