QT-多线程、线程池的使用

news/2024/10/7 17:58:35 标签: qt, 多线程

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

qt 中使用了多线程,有些事项是需要额外注意的:

  • 默认的线程在Qt中称之为窗口线程,也叫主线程,负责窗口事件处理或者窗口控件数据的更新
  • 子线程负责后台的业务逻辑处理,子线程中不能对窗口对象做任何操作,这些事情需要交给窗口线程处理
  • 主线程和子线程之间如果要进行数据的传递,则需要使用Qt中的信号槽机制

一、QT多线程实现方法(1)- 基于QThread

  • 创建subThread线程类,继承QThread类
  • 重写父类的run()方法,即具体要执行的任务
  • 主线程中创建子线程对象,调用start()方法启动子线程

二、QT多线程实现方法(2)- 基于QObject

  • 创建工作类,继承QObject类
  • 添加一个公共的成员函数,函数体就是子线程要执行的业务逻辑(后面把这个任务函数作为槽函数使用)
  • 主线程中创建子线程对象
  • 创建工作类对象(注意不能给他指定父对象)
  • 将工作类对象移动到创建的子线程的对象中,需要调用QObject的moveToThread()方法
  • 启动子线程,调用start()方法,但此时线程虽然启动了,但移动到线程中的对象没有工作
  • 调用工作类对象的工作函数,让这个函数执行业务

第二种方法更灵活,一个工作类可以有多个工作函数,多个工作对象也可以移动到同一个子线程中,可以人为控制指定线程执行指定任务。在第一种方法中,如果run函数需要传入的数据,可以通过信号槽机制+成员变量的形式实现接收,工作函数run函数是不能直接传入参数的;而在第二种方法中,工作函数是可以有参数的,可以通过信号槽机制直接传入数据,而不用再定义成员变量。
第一种方法简单,只需要书写线程类,重写run函数,然后在主线程中创建子线程对象,通过这个子线程对象调用start方法工作。弊端就是,如果需求、任务足够多,写入到run函数中,判定就复杂,run函数也越臃肿,因此在任务简单、少的情况下使用第一种方法

需要注意的一个点,使用connect(发出者,信号,接收者,处理函数)时,

connect(gen,&Generate::sendArray,bubble,&BubbleSort::working);
connect(gen,&Generate::sendArray,quick,&QuickSort::working);
//上下两种是不一样的,下面变成了在主线程里处理,因为bubble对象移动到了子线程里,
//所以bubble->working()也是在子线程下执行的
connect(gen,&Generate::sendArray,this,[=](QVector<int> list){
	bubble->working();
	quick->working();
});
    

三、线程资源释放

创建子线程对象时指定父对象,这样Qt就会自动回收这些资源,按照QT的内存回收机制,第一个是指定的父对象得是QObejct类的子类或者间接子类,第二个就是创建对象时必须指定父对象,父对象析构的时候会根据对象树先析构子对象
第二种方式在当前窗口类的析构函数中释放掉这些资源,就是手动析构。当然写的程序有时候析构函数是访问不到哪些子线程对象的,如果不想把这些子线程对象设置为窗口类的成员变量,那我们还可以通过信号-槽的机制来回收这些资源,窗口关闭时发出destroed的信号,这里利用信号槽,收到这个信号时释放掉子线程对象、任务对象的资源

    connect(this, &MainWindow::destroyed, this, [=]()
    {
        t1->quit();
        t1->wait();
        t1->deleteLater();
        
        t2->quit();
        t2->wait();
        t2->deleteLater();
        
        t3->quit();
        t3->wait();
        t3->deleteLater();
        
        gen->deleteLater();  // delete t1;
        bubble->deleteLater();
        quick->deleteLater();
    });

四、线程池

Qt提供了QThreadPool线程池类,然后有一列的API

// 在每个Qt应用程序中都有一个全局的线程池对象, 通过这个函数直接访问这个对象
static QThreadPool * QThreadPool::globalInstance();
//调用start方法,把任务封装成QRunnable 对象,扔给线程池,线程池下的空闲线程就会帮我们处理对应任务
//QRunnable * runnable 任务的类型,QRunnable 主要是run函数和设置释放自动析构的API
//priority 优先级
void QThreadPool::start(QRunnable * runnable, int priority = 0);

  • 先创建一个要添加到线程池中的任务类,继承QObject(可以使用信号槽机制)、QRunnable
  • 重写run 方法(继承Qthread的run是protected,而QRunnable 的run是public),里面就是执行任务,另外还需要在构造函数里设置自动析构
  • 主函数中创建任务对象,调用QThreadPool::globalInstance()->start(task)执行任务;

五、基于线程池执行多任务

基于线程池可以将方法(1)的多线程修改为线程池实现多任务

参考博客


http://www.niftyadmin.cn/n/5693152.html

相关文章

单细胞组学大模型(6)--- LangCell,医学/细胞文本知识增强模型效果

–https://arxiv.org/abs/2405.06708 代码开源&#xff1a;https://github.com/PharMolix/OpenBioMed LangCell: Language-Cell Pre-training for Cell Identity Understanding 留意更多内容&#xff0c;欢迎关注微信公众号&#xff1a;组学之心 研究团队和研究单位 聂再清…

大数据新视界 --大数据大厂之 Alluxio 数据缓存系统在大数据中的应用与配置

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

服务无法启动

有个服务死活无法启动了&#xff0c;运行就直接退出&#xff0c;无任何日志。 调试程序&#xff0c;能进入main函数&#xff0c;能进入SpringApplication.run 说明底层无误。 各种折腾无果。 最终既然没有日志&#xff0c;应该是日志出了问题&#xff0c;问开发是否改配置&a…

Rust-枚举

Rust-枚举 本文介绍 Rust 枚举&#xff08;enumerations&#xff09;&#xff0c;也被称作 enums。 枚举允许你通过列举可能的 成员&#xff08;variants&#xff09; 来定义一个类型。 首先&#xff0c;我们会定义并使用一个枚举来展示它是如何连同数据一起编码信息的。接下…

基于深度学习的视频中的姿态跟踪

基于深度学习的视频姿态跟踪是一项用于从视频序列中持续检测和跟踪人体姿态的技术。它能够识别人体的2D或3D关键点&#xff0c;并在时间维度上进行跟踪&#xff0c;主要应用于人机交互、体育分析、动作识别和虚拟现实等领域。以下是视频姿态跟踪的主要原理和方法&#xff1a; …

开源跨平台三维模型轻量化软件osgGISPlugins-2、如何编译

上一篇&#xff1a;开源跨平台三维模型轻量化软件osgGISPlugins-1、简介 1、编译前的准备&#xff1a;安装、配置vcpkg包管理器 1&#xff09;安装及国内镜像替换教程(Windows和Linux环境都有):vcpkg国内镜像源替换 2&#xff09;下载第三方依赖库(Readme文档中所给出的百度网…

[C#]使用onnxruntime部署yolov11-onnx实例分割模型

【官方框架地址】 https://github.com/ultralytics/ultralytics.git 【算法介绍】 在C#中使用ONNX Runtime部署YOLOv11-ONNX实例分割模型&#xff0c;涉及到模型的加载、数据预处理、模型推理和后处理几个关键步骤。 首先&#xff0c;需要确保已经安装了ONNX Runtime的NuGe…

李宏毅 X 苹果书 自注意力机制 学习笔记下

b1 &#xff0c;b2...不是依序产生&#xff0c;而是同时被计算好的 从矩阵乘法角度看待self-attention运作过程 矩阵运算表示每一个a都要产生 a k v的操作如下&#xff1a; 矩阵运算表示的计算如下&#xff1a; A‘是A的normalization &#xff0c;用softmax 矩阵运算表示b计…