QT 异步编程之多线程

news2025/2/21 9:05:58

一、概述

1、在进行桌面应用程序开发的时候,假设应用程序在某些情况下需要处理比较复制的逻辑,如果只有一个线程去处理,就会导致窗口卡顿,无法处理用户的相关操作。这种情况下就需要使用多线程,其中一个线程处理窗口事件,其它线程进行逻辑运算,多个线程各司其职,不仅可以提高用户体验还可以提升程序的执行效率。

2、当前的主线程不能让它做非常复制的逻辑操作,如果你让它做了非常复杂的逻辑操作后,咱们再操作这个窗口的时候就会出现界面的卡顿,那么这些复杂的操作应该交给子线程去做。

3、默认的线程在Qt中称之为窗口线程,也叫主线程,负责窗口事件处理或者窗口控件数据的更新。

4、子线程复制后台的业务逻辑处理,子线程中不能对窗口对象做任何操作,这些事情需要交给窗口线程处理。

5、主线程和子线程之间如果要进行数据的传递,需要使用Qt中的信号与槽机制

二、多线程的使用方式一

1、需要创建一个线程的子类,让其继承QT中的线程类QThread

class MyThread : public QThread
{
    ...............
}

2、重写父类的run方法,在该函数内部编写子线程要处理的具体的业务流程

class MyThread : public QThread
{
    .........
protected:
    void run()
    {
        ........
    }
}

3、在主线程中创建子线程对象,new一个就可以了

MyThread *subThread = new MyThread;

 4、启动子线程,调用start()方法

subThread->start();

5、示例 MyThread.h

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QObject>
#include <QThread>

class MyThread : public QThread
{
    Q_OBJECT
public:
    MyThread();

    void print();

protected:
    void run() override;

signals:
};

#endif // MYTHREAD_H

6、 示例 MyThread.cpp

#include "mythread.h"
#include <QDebug>

MyThread::MyThread()
{
}

void MyThread::print()
{
    qDebug() << "子线程成员函数的线程ID:" << QThread::currentThreadId();
}

void MyThread::run()
{
    qDebug() << "子线程的线程ID:" << QThread::currentThreadId();
}

7、main函数

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    MyThread w;
    w.start();

    qDebug() << "主线程ID:" << QThread::currentThreadId();

    w.print();

    return a.exec();
}

8、结果展示

 9、结果分析:

(1)主线程和子线程的顺序不确定,偶尔主线程在前,偶尔子线程在前

(2)子线程类的成员函数包括槽函数是运行在主线程当中的,只有run()函数运行在子线程中

(3)如果run()函数中调用子线程的成员函数,那么该成员函数运行在子线程中

二、多线程的使用方式二

 1、创建一个新的类,让这个类从QObject派生

class MyWork : public QObject
{
    .........
}

2、在这个类中添加一个公共的成员函数,函数体就是我们要子线程中要执行的业务逻辑

class MyWork : public QObject
{
public:
    ......
    //函数名自己指定,叫什么都可以
    void working();
}

3、在主线程中创建一个QThread对象,这就是子线程的对象

QThread *sub = new QThread;

4、在主线程中创建工作的类对象(不要给创建的对象指定父对象)

MyWork *work = new MyWork(this);  //error
MyWork *work = new MyWork;        //ok

5、将MyWork对象移动到创建的子线程对象中,需要调用QObject类提供的moveToThread()方法

work->moveToThread(sub);

6、启动子线程,调用start(),这时候线程启动了,但是移动到线程中的对象并没有工作

7、调用MyWork类对象的工作函数,让这个函数开始执行,这时候是在移动到的那个子线程中运行的

8、示例 MyWork.h

#ifndef MYWORK_H
#define MYWORK_H

#include <QObject>

class MyWork : public QObject
{
    Q_OBJECT
public:
    explicit MyWork(QObject *parent = nullptr);

    void print();

public slots:
    void doWork();

signals:
};

#endif // MYWORK_H

9、示例 MyWork.cpp

#include "mywork.h"
#include <QDebug>
#include <QThread>

MyWork::MyWork(QObject *parent)
    : QObject{parent}
{
}

void MyWork::print()
{
    qDebug() << "成员函数ThreadID:" << QThread::currentThreadId();
}

void MyWork::doWork()
{
    qDebug() << "doWork ThreadId:" << QThread::currentThreadId();
}

10、示例 main

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QThread *thread = new QThread();
    MyWork *worker = new MyWork;
    worker->moveToThread(thread);

    QObject::connect(thread, &QThread::started, worker, &MyWork::doWork);
    QObject::connect(thread, &QThread::started, worker, &MyWork::print);

    qDebug() << "主线程ID:" << QThread::currentThreadId();

    //启动线程
    thread->start();

    //调用成员函数
    worker->print();

    return a.exec();
}

 11、运行结果

22:38:21: Starting D:\QT\practice\mouseTrack\bin\debug\untitled.exe...
主线程ID: 0x56f0
成员函数ThreadID: 0x56f0
doWork ThreadId: 0x49d4
成员函数ThreadID: 0x49d4

 12、结果分析

(1)通过信号与槽触发的成员函数、槽函数,执行都在新线程里面,通过对象调用执行,则在旧线程里面

三、两种方式的使用场景

1、QThread使用场景

(1)当需要创建一个独立的线程来执行某个任务,且需要对线程的整个生命周期进行管理时,适合使用 QThread 方式。

(2)当任务逻辑相对简单或独立,不需要频繁地进行线程间通信时,可以选择使用 QThread 方式。

2、moveToThread方式

(1)当需要将一个 QObject 对象移动到指定的线程中执行任务,或者需要多个对象在同一线程中协同工作时,适合使用 moveToThread() 方式。

(2)当需要灵活地控制对象和线程之间的关系,进行复杂的线程间通信时,可以选择使用 moveToThread() 方式。

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

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

相关文章

Proxmox 更新软件包数据库(TASK ERROR: command ‘apt-get update‘ failed: exit code 100)

1、连接自己报错的物理机Shell&#xff0c;编辑文件 vi /etc/apt/sources.list.d/pve-enterprise.list 2、注释文件的第一行在开头加上# 按I进入编辑模式后 开头添加# 然后shift&#xff1a; 输入wq或者wq&#xff01;进行保存 3、注释后执行两个命令apt-get update 和 apt…

JVM——垃圾回收算法

目录 垃圾回收算法 评价标准&#xff1a; 标记-清除算法&#xff1a; 复制算法&#xff1a; 标记-整理算法&#xff1a; 分代GC&#xff1a; arthas查看分代之后的内存情况&#xff1a; 垃圾回收算法 java是如何实现垃圾回收的呢&#xff1f;简单来说&#xff0c;垃圾回…

服务器安全——日志分析和扫描

如何通过访问日志查询被攻击 扫描攻击 攻击日志 GET /index?sindex/%5Cthink%5CModule/Action/Param/$%7Bphpinfo()%7D HTTP/1.1", host: "主机", referrer: "主机sindex/\think\Module/Action/Param/${phpinfo()}" 攻击日志文件 .error.log sql注…

ubuntu 22.04 安装vsftpd服务

先决条件&#xff0c;确保你已经配置好了存储库。 安装vsftpd 为了方便实验&#xff0c;我已经切换到了root用户。 rootlocal:~# apt-get install vsftpd修改配置 配置文件在 /etc/vsftpd.conf rootlocal:~# grep -vE ^#|^$ /etc/vsftpd.conf listenNO listen_ipv6YES anonymou…

STM32F407通过FSMC扩展外部SRAM和NAND FLASH

1 扩展外部SRAM 1.1 地址情况 FSMC控制器的存储区分为4个区(Bank)&#xff0c;每个区256MB。其中&#xff0c;Bank1可以用于连接SRAM、NOR FLASH、PSRAM&#xff0c;还可以连接TFT LCD。Bank1的地址范围是0x60000000&#xff5e;0x6FFFFFFF。Bank1又分为4个子区&#xff0c;每…

AndroidStudio查看Sqlite和SharedPreference

1.查看Sqlite 使用App Inspection&#xff0c;这是个好东西 打开方式&#xff1a;View → Tool Windows → App Inspection 界面如图&#xff1a; App inspection不但可以看Sqlite还可以抓包network和background task连抓包工具都省了。 非常好使 2.查看sharedPreference 使…

Elasticsearch:15 年来致力于索引一切,找到重要内容

作者&#xff1a;来自 Elastic Shay Banon 及 Philipp Krenn Elasticsearch 刚刚 15 岁了&#xff01;回顾过去 15 年的索引和搜索&#xff0c;并展望未来 15 年的相关内容。 Elasticsearch 刚刚成立 15 周年。一切始于 2010 年 2 月的一篇公告博客文章&#xff08;带有标志性的…

信呼OA办公系统sql注入漏洞分析

漏洞描述 信呼OA办公系统uploadAction存在SQL注入漏洞&#xff0c;攻击者可利用该漏洞获取数据库敏感信息。 环境搭建 源码下载地址&#xff1a;https://github.com/rainrocka/xinhu 下载后解压到本地网站根目录下&#xff0c;配置好数据库&#xff0c;然后安装即可 默认密…

机器学习算法 - 随机森林之决策树初探(1)

随机森林是基于集体智慧的一个机器学习算法&#xff0c;也是目前最好的机器学习算法之一。 随机森林实际是一堆决策树的组合&#xff08;正如其名&#xff0c;树多了就是森林了&#xff09;。在用于分类一个新变量时&#xff0c;相关的检测数据提交给构建好的每个分类树。每个…

原生Three.js 和 Cesium.js 案例 。 智慧城市 数字孪生常用功能列表

对于大多数的开发者来言&#xff0c;看了很多文档可能遇见不到什么有用的&#xff0c;就算有用从文档上看&#xff0c;把代码复制到自己的本地大多数也是不能用的&#xff0c;非常浪费时间和学习成本&#xff0c; 尤其是three.js &#xff0c; cesium.js 这种难度较高&#xff…

在 PyCharm 中接入deepseek的API的各种方法

在 PyCharm 中接入 DeepSeek 的 API&#xff0c;通常需要以下步骤&#xff1a; 1. 获取 DeepSeek API 密钥 首先&#xff0c;确保你已经在 DeepSeek 平台上注册并获取了 API 密钥&#xff08;API Key&#xff09;。如果没有&#xff0c;请访问 DeepSeek 的官方网站注册并申请 …

【2025新】基于springboot的问卷调查小程序设计与实现

目录 一、整体目录&#xff08;示范&#xff09;&#xff1a; 文档含项目技术介绍、E-R图、数据字典、项目功能介绍与截图等 二、运行截图 三、代码部分&#xff08;示范&#xff09;&#xff1a; 四、数据库表(示范)&#xff1a; 数据库表有注释&#xff0c;可以导出数据…

数据结构——Makefile、算法、排序(2025.2.13)

目录 一、Makefile 1.功能 2.基本语法和相关操作 &#xff08;1&#xff09;创建Makefile文件 &#xff08;2&#xff09;编译规则 &#xff08;3&#xff09;编译 &#xff08;4&#xff09;变量 ①系统变量 ②自定义变量 二、 算法 1.定义 2.算法的设计 &#xff…

什么是Docker多架构容器镜像

什么是Docker多架构容器镜像 在 Docker 中&#xff0c;同一个 Docker 镜像可以在不同的平台上运行&#xff0c;例如在 x86、ARM、PowerPC 等不同的 CPU 架构上。 为了支持这种多平台的镜像构建和管理&#xff0c;Docker 在 17.06 版本时引入了 Manifest 的概念&#xff0c;在…

【devops】 Git仓库如何fork一个私有仓库到自己的私有仓库 | git fork 私有仓库

一、场景说明 场景&#xff1a; 比如我们Codeup的私有仓库下载代码 放入我们的Github私有仓库 且保持2个仓库是可以实现fork的状态&#xff0c;即&#xff1a;Github会可以更新到Codeup的最新代码 二、解决方案 1、先从Codeup下载私有仓库代码 下载代码使用 git clone 命令…

RocketMQ及和Kafka的区别

目录 1 从场景入手2 RocketMQ是什么&#xff1f;3 RocketMQ及和Kafka的区别3.1 在架构上做了减法3.1.1 简化协调节点3.1.2 简化分区3.1.3 底层存储3.1.3.1 Kafka底层存储3.1.3.1 RocketMQ底层存储 3.1.4 简化备份模型3.1.4.1 Kafka备份模型3.1.4.2 RocketMQ备份模型 3.1.5 Rock…

【含文档+PPT+源码】基于微信小程序的乡村振兴民宿管理系统

项目介绍 本课程演示的是一款基于微信小程序的乡村振兴民宿管理系统&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的 Java 学习者。 1.包含&#xff1a;项目源码、项目文档、数据库脚本、软件工具等所有资料 2.带你从零开始部署运行本套系统 3.该…

Datawhale Ollama教程笔记3

小白的看课思路&#xff1a; Ollama REST API 是什么&#xff1f; 想象一下&#xff0c;你有一个智能的“盒子”&#xff08;Ollama&#xff09;&#xff0c;里面装了很多聪明的“小助手”&#xff08;语言模型&#xff09;。如果你想让这些“小助手”帮你完成一些任务&#…

基于JavaWeb开发的Java+Spring+vue+element实现旅游信息管理平台系统

基于JavaWeb开发的JavaSpringvueelement实现旅游信息管理平台系统 &#x1f345; 作者主页 网顺技术团队 &#x1f345; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; &#x1f345; 文末获取源码联系方式 &#x1f4dd; &#x1f345; 查看下方微信号获取联系方式 承接各…

【技术产品】DS三剑客:DeepSeek、DataSophon、DolphineSchduler浅析

引言 在大数据与云原生技术快速发展的时代&#xff0c;开源技术成为推动行业进步的重要力量。本文将深入探讨三个备受瞩目的开源产品组件&#xff1a;DeepSeek、DataSophon 和 DolphinScheduler&#xff0c;分别从产品定义、功能、技术架构、应用场景、优劣势及社区活跃度等方面…