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

这篇具有很好参考价值的文章主要介绍了【Qt】QThread & 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 的类
【Qt】QThread & moveTothread-多线程的两种实现方法,Qt,qt,开发语言
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_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    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
    //执行打印主函数线程ID
    qDebug()<<"主线程ID:" <<QThread::currentThreadId()<<'\n';
    //链接(主线程)信号和(子线程)信号槽,并发射信号触发子线程信号槽打印其目前的线程ID
    connect(this,&MainWindow::mainwindownSignal,myThread,&thread_1::thread1Slot);
    emit mainwindownSignal();
}

结果展示
① 结果让我有些意外,明明是让子线程先运行的,但是最先运行的是主线程,然后其次是子线程的槽函数,最后才是子线程的运行。
② 另外从图中可以看到,子线程的槽函数竟然处于主线程中!
【Qt】QThread & moveTothread-多线程的两种实现方法,Qt,qt,开发语言

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_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
//step3:在 mainwindow.h 中创建 work 和 QThread 的对象:worker 和myThread
    Ui::MainWindow *ui;
    work* worker;
    QThread* myThread;
signals:
//step4:在 mainwindow.h 中写触发 worker 槽函数的信号mainwindownSignal
    void 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);//moveTothread
    myThread->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 去掉注释看看)
【Qt】QThread & moveTothread-多线程的两种实现方法,Qt,qt,开发语言

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

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

【Qt】QThread & moveTothread-多线程的两种实现方法,Qt,qt,开发语言

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


参考教程:
Qt 教程-爱编程的大丙
Qt 串口多线程 继承QThread_pyqt串口多线程-CSDN博客
QThread的用法-CSDN博客文章来源地址https://www.toymoban.com/news/detail-789951.html

到了这里,关于【Qt】QThread & moveTothread-多线程的两种实现方法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Qt多线程使用的两种方式

    方式1 :继承自QThread类,重载run函数。此实现方法只有run()函数内的代码是运行在子线程内。 (不使用事件循环) 使用方法 : (1)run函数内有一个while或for的死循环(模拟耗时操作); (2)通过一个 标记位 来控制死循环的退出; (3)run()函数中无限循环记得 强制休息

    2023年04月10日
    浏览(33)
  • Qt创建右键菜单的两种通用方法(QTableView实现右键菜单,含源码+注释)

    下图为两种右键菜单实现的示例图,源码在本文第三节(源码含详细注释)。 提示:不会使用Qt设计师设计界面的小伙伴点击这里。 该方法是触发contextMenuEvent事件来实现右键菜单,只需在该事件函数中写入对应的右键菜单代码即可。 该方法是通过控件发出的customContextMenuR

    2024年02月15日
    浏览(31)
  • QT -- 多线程 —— moveToThread

    视频教程链接: https://www.bilibili.com/video/BV1fL4y1V7QP/?spm_id_from=333.880.my_history.page.clickvd_source=b91967c499b23106586d7aa35af46413 moveToThread函数的功能:给多个任务(比如显示多个界面)各分配一个线程去执行。这样就避免了自定义好多个类继承自QThread类,从而可以避免冗余。 翻译:更改

    2024年01月25日
    浏览(26)
  • Qt+OpenCV显示图片的两种方法(代码演示)

    导  读     本文主要介绍Qt+OpenCV显示图像的两种方法,并通过代码演示效果。 背景介绍     OpenCV本身提供了一些GUI方法,但使用起来仍有局限性。以C++为例,实际应用中我们大多会使用Qt或MFC来编写GUI程序。相较之下,Qt比MFC更易上手且界面样式更丰富,所以越来越多的

    2024年02月07日
    浏览(32)
  • QT学习之旅 - QThread多线程

    其实QT中的thread(线程)是很容易的 首先是主线程 其次是一个程序 通过一个QThread来放入程序 一个简单的线程就实现了 进阶一点: 手动开启关闭线程 添加一个按键,通过 信号和槽 来控制线程使能关闭 Test不变。 现象 是 mainwindow i:99(执行完) 后窗口出现,之后 开启线程 。开启后

    2024年02月16日
    浏览(34)
  • 使用Qt Designer为您的Qt for Python项目创建基于Qt Widgets的图形界面的两种方法

    本页介绍如何使用Qt Designer为您的Qt for Python项目创建基于Qt Widgets的图形界面。Qt Designer是一个图形UI设计工具,可以作为独立的二进制文件(pyside6-designer)提供,也可以嵌入到Qt Creator IDE中。它在Qt Creator中的使用在Using Qt Designer中描述。 设计存储在.ui文件中,这是一种基于

    2024年02月07日
    浏览(33)
  • C++ Qt开发:运用QThread多线程组件

    Qt 是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍如何运用 QThread 组件实现多线程功能。 多线程技术在程序开发中尤为常用,Q

    2024年03月09日
    浏览(42)
  • 【QT多线程一】继承QThread,重写run函数

    Qt有两种多线程的方法,其中一种是继承QThread的run函数,另外一种是把一个继承于QObject的类转移到一个Thread里 。 在这里先介绍一下qt多线程的第一种实现方法,继承qthread并重写run函数。 注意 :QThread只有run函数是在新线程里的,其他所有函数都在QThread生成的线程里。如果

    2024年02月14日
    浏览(24)
  • 线程方法接收参数示例,Java的两种线程实现方式区别

    总所周知,Java实现多线程有两种方式,分别是继承Thread类和实现Runable接口,那么它们的区别是什么? 继承 Thread 类: 通过继承 Thread 类,你可以创建一个直接表示线程的类。你可以覆盖 Thread 类中的 run 方法来定义线程的逻辑。当调用 start 方法启动线程时,会执行该类中的

    2024年02月11日
    浏览(30)
  • QT中Qthread线程彻底销毁的实例与注意事项(防止线程资源内存泄露)

     注意: 释放线程的时候触发线程的信号与槽连接时的连接类型参数一定要是Qt::ConnectionType::DirectConnection, 否则线程销毁不了会造成内存泄露,通过任务栏开启资源管理器可监视cup的线程数变化情况。 QThread* th=new QThread();           Work* mywork=new Work ();           mywork-move

    2024年02月02日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包