首页 > 其他分享 >Qt 中的多线程 02:移动工作对象到子线程中

Qt 中的多线程 02:移动工作对象到子线程中

时间:2023-12-27 16:47:22浏览次数:47  
标签:02 到子 执行 void QThreadTest MyWork 线程 多线程 QThread

Qt 中的多线程除了通过继承 QThread 类,然后重写虚函数 run() 之外还有另一种方案:将要执行的复杂操作,放在一个继承自 QObject 的类中,然后使用 QObject::moveToThread(QThread*) 函数将工作对象的移动到创建的子线程中去执行。

工作对象类

该类继承自 QObject 主要是用来实现一些耗时复杂的操作,这些操作可能会阻塞主线程,因此需要在后面将其移到子线程中去执行。

1、MyWork.h 文件

#pragma once

#include <QObject>

class MyWork: public QObject
{
    Q_OBJECT
public:
    MyWork();
    ~MyWork();

signals:

    /**
     * 子线程用来向主线程发送信号.
     */
    void  SendMsg(QString msg);

public slots:

    /**
     * 复杂操作在槽函数中实现,然后通过信号槽来与主线程建立联系
     * 以触发该复杂的槽函数执行。
     */
    void DoSomething();

};

2、MyWork.cpp 文件

#include "MyWork.h"
#include <QThread>

MyWork::MyWork()
{

}

MyWork::~MyWork()
{

}

void MyWork::DoSomething()
{
    SendMsg(QString("子线程id = %1").arg((int)QThread::currentThreadId()));
    SendMsg("Begin Work ......");

    QThread::sleep(6);

    SendMsg("Work Finished.");
}

主线程类

将在主线程类中去创建子线程,和 工作对象,并将工作对象移动到子线程中,然后通过主程序的信号来触发位于子线程中的工作对象,让其执行一些复杂的操作。

1、QThreadTest.h 文件

#pragma once

#include <QtWidgets/QMainWindow>
#include "ui_QThreadTest.h"
#include <QThread>

#include "MyWork.h"

class QThreadTest : public QMainWindow
{
    Q_OBJECT

public:
    QThreadTest(QWidget *parent = Q_NULLPTR);
    ~QThreadTest();

signals:

    /**
     *  主线程通过触发信号,来让子线程开始执行工作.
     */
    void BeginWork();

private slots:
    /**
     * 直接在主线程中进行耗时操作,会直接阻塞主UI线程,导致程序卡死.
     */
    void OnBtn01Clicked();

    /**
    * @brief  通过点击Button来触发对应的信号,然位于子线程中的工作对象开始执行对应的函数
    */
    void OnBtn02Clicked();

    /**
    * @brief  由于子线程不能直接操作UI,所以该函数用于将接受到的子线程内容显示在UI上
    * @param  [in]  msg
    */
    void GetWorkMsg(QString msg);

private:
    Ui::QThreadTestClass ui;
    QThread *subThread;     // 创建子线程,用来将任务移动到该线程中去执行
};

2、QThreadTest.cpp 文件

#include "QThreadTest.h"
#include <QPushButton>

QThreadTest::QThreadTest(QWidget *parent)
    : QMainWindow(parent)
{
    ui.setupUi(this);

    subThread = new QThread(this);

    // 创建工作对象,不能为其指定父指针,否则后面无法将其移动子线程中去执行
    MyWork* myWork = new MyWork();

    // 将工作对象移动到子线程中去执行
    myWork->moveToThread(subThread);

    // 在子线程执行结束之后,将工作对象的资源进行释放
    connect(subThread, &QThread::finished, myWork, &MyWork::deleteLater);

    // 通过主线程的信号来触发子线程开始执行对应的工作
    connect(this, &QThreadTest::BeginWork, myWork, &MyWork::DoSomething);

    // 在子线程中的工作对象无法直接修改主线程的UI,因此需要通过信号槽的方式来进行更新
    connect(myWork, &MyWork::SendMsg, this, &QThreadTest::GetWorkMsg);

    // 启动子线程,此时只是子线程开始执行,但是子线程中的具体工作 DoSomething 还未执行
    subThread->start();


    connect(ui.btn01, &QPushButton::clicked, this, &QThreadTest::OnBtn01Clicked);
    connect(ui.btn02, &QPushButton::clicked, this, &QThreadTest::OnBtn02Clicked);
}

QThreadTest::~QThreadTest()
{
    // 创建的线程一定要进行释放,否则关闭程序的时候线程仍然在运行,此时会造成程序Crash
    subThread->quit();
    subThread->wait();
}

void QThreadTest::OnBtn01Clicked()
{
    ui.textBrowser_01->append("Start do something ...");

    QThread::sleep(5);

    ui.textBrowser_01->append("Finishing this operation.");
}

void QThreadTest::OnBtn02Clicked()
{
    ui.textBrowser_02->append(QString("主线程id = %1").arg((int)QThread::currentThreadId()));

    emit BeginWork(); // 触发信号,子线程中开始执行工作对象的函数
}

void QThreadTest::GetWorkMsg(QString msg)
{
    ui.textBrowser_02->append(msg);
}


【总结】

该方法的主要流程为:

  1. 创建一个类,如 MyWork 继承自 QObject
  2. MyWork 类中将复杂的操作放在槽函数中,后续会通过信号槽的方式来触发子线程执行该操作。
  3. MyWork 类中定义信号槽,用于子线程向主线程更新数据或信息。
  4. 在主线程中创建 QThread 对象,和 MyWork类对象,并将 工作对象移动到子线程中。
  5. 分别建立信号槽:
    • 子线程执行完工作后,释放工作对象。(此时子线程可能并未退出)
    • 主线程的开始执行信号连接工作对象的槽函数。
    • 子线程向主线程发送数据,用来更新UI或同步操作。
  6. 启动子线程,此时工作对象的复杂操作还未执行。
  7. 在主线程中某一时机下,触发开始在子线程中执行工作类中的槽函数,此时才会进行复杂操作的执行。

标签:02,到子,执行,void,QThreadTest,MyWork,线程,多线程,QThread
From: https://www.cnblogs.com/Jeffxu/p/17930834.html

相关文章

  • 雅礼 2023.12.27 习题课记录
    雅礼2023.12.27习题课记录前言这一场罚时多,都是一些低级错误。好吧全都是水题。水题(只放代码)莫诺卡普参加了一场编程比赛,其中包括\(26\)个问题,从A到Z命名。问题按难度排序。此外,已知莫诺卡普可以在\(1\)分钟内解决问题A,在\(2\)分钟内解决问题B,\(\dots\),在\(2......
  • 2023年十大网络安全攻击事件
    1、ESXi勒索软件攻击今年2月,“ESXiArgs”组织针对运行VMwareESXi虚拟机监控程序的客户展开勒索攻击。据联邦调查局(FBI)和CISA数据估计,全球受感染的服务器数量超过了3800台。网络安全供应商Censys称,该活动主要针对美国、加拿大、法国和德国等国家的组织。研究人员表示:这些攻......
  • 2023NCTF Misc Crypto 部分WP
    MISCJumpForSignin题目来签个到吧我的解答:哎!游戏题。。直接打开这个文件运行玩游戏,进入游戏后点击空格进行跳跃,会看到天上掉落二维码,截图即可。在线工具扫码即可https://demo.dynamsoft.com/barcode-reader/?ref=www.hackjie.comNCTF{VVVVELCOME_TO_NCTF_2023!^!}......
  • 2023-12-27:用go语言,店铺数量n,编号1~n, 人的数量m,编号1~m, 每个人有自己投票的店铺p,和改
    2023-12-27:用go语言,店铺数量n,编号1~n,人的数量m,编号1~m,每个人有自己投票的店铺p,和改投1号店的报价x。返回想让1号店铺成为人气最高的店,至少花多少钱?1<=p,n,m<=3000,1<=x<=10^9。1号店铺贿赂问题。来自华为OD。答案2023-12-27:来自左程云。灵捷3.5大体步骤如下:minC......
  • [NOIP2023] 词典
    题目描述小S的词典里有\(n\)个两两不同的、长度均为\(m\)的单词\(w_1,w_2,\cdots,w_n\)。每个单词都是一个小写字母构成的字符串。小S可以做以下操作任意多次(可以不做):选择词典中的任意一个单词,交换其中任意两个字符。对于每个\(1\lei\len\),小S想知道,是否可以通......
  • 2023年航天大事件
    2023年,中国完成宇航发射近70次,是中国航天新的里程碑。中国科技工作者继续推进航天科技创新,并在运载火箭发动机研制固体燃料火箭研发、可重复航天器研发等方面取得重大突破;继续推进载人航天工程、北斗工程等中国重大航天旗舰工程,打造大型空间基础设施;继续推进遥感卫星、通讯卫星等......
  • 02-Mysql体系结构
    一、MySQL服务器连接模型2、应用程序如何连接到mysql2.1tcp/ip的方式mysql-uroot-poldboy123-h10.0.0.2002.2套接字的方式mysql-uroot-poldboy123-S/tmp/mysql.sock二、MySQL服务器构成——实例连接层sql层处理流程解析器(执行计划)--优化器(选择比......
  • 2024 商旅费控趋势洞察与前瞻!
    随着全球经济的不断发展和企业管理需求的日益复杂化,高效、智能的商旅费控系统已成为企业运营不可或缺的一部分。即将迈入2024年,当企业的降本指标不断加压、数字化转型战略亟待落地、员工出行体验不容忽视、财务报销与管控日益严苛……企业商旅及费控业务应如何应对?为迎接商旅费控的......
  • 百度网盘(百度云)SVIP超级会员共享账号每日更新(2023.12.27)
    一、百度网盘SVIP超级会员共享账号可能很多人不懂这个共享账号是什么意思,小编在这里给大家做一下解答。我们多知道百度网盘很大的用处就是类似U盘,不同的人把文件上传到百度网盘,别人可以直接下载,避免了U盘的物理载体,直接在网上就实现文件传输。百度网盘SVIP会员可以让自己百度账......
  • 题解 P9993【[Ynoi Easy Round 2024] TEST_133】
    就硬把线段树3和数列分块入门2揉到一起出。维护原数组\(a\)及其历史最大值\(hist\),对每个块,维护块内\(a\)升序排序后结果\(p\)、块内\(a\)升序排序后历史最大值前缀和\(prehist\)、块加标记\(add\)、块历史和加标记\(histadd\)。下传标记和区间修改操作仿照线......