1. Qt多线程开发

目录

  • 方法1.继承QThread
    • 使用案例
    • 总结
  • 方法2.将qobject对象moveToThread(官方推荐)
    • 使用案例
    • 总结
  • 方法3.QRunnable + QThreadPool
    • 使用案例
    • 总结
  • 方法4.快速线程QtConcurrent+QFutureWatcher
    • 使用案例
    • 总结
  • 代码下载

方法1.继承QThread

需要实现QThread的抽象函数run

#ifndef WORKERTHREAD_H
#define WORKERTHREAD_H#include <QObject>
#include <QThread>
#include <QDebug>class WorkerThread : public QThread
{Q_OBJECT
public:explicit WorkerThread(QObject *parent = nullptr);void func1();protected:virtual void run();signals:
};#endif // WORKERTHREAD_H#include "workerthread.h"WorkerThread::WorkerThread(QObject *parent): QThread{parent}
{}void WorkerThread::func1()
{qDebug()<< __FUNCTION__<< QThread::currentThread();
}void WorkerThread::run()
{qDebug()<< __FUNCTION__<< QThread::currentThread();
}

使用案例

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);qDebug()<< "主线程:" << QThread::currentThread();wt = new WorkerThread(this);wt->start();//执行WorkerThread的run在子线程中wt->func1();    //主线程connect(ui->pushButton,&QPushButton::clicked,wt,&WorkerThread::func1); //主线程}Widget::~Widget()
{delete ui;
}

总结

run函数是在子线程中执行的
其成员函数func1
a)直接调用的方式是在创建对象的线程(主线程)中执行的
b)信号槽连接的方式也是在创建对象的线程(主线程)中执行的

直接调用接口,如果包含了run线程中使用的变量可能就会导致数据竞争
此时就得考虑加锁
如果run线程中获取到了锁,主线程调用WorkerThread的接口会导致阻塞,界面卡顿=
使用场景,不需要进行线程间数据交互

方法2.将qobject对象moveToThread(官方推荐)

#ifndef WORKER_H
#define WORKER_H#include <QObject>class Worker : public QObject
{Q_OBJECT
public:explicit Worker(QObject *parent = nullptr);~Worker();void func1();signals:
};#endif // WORKER_H
#include "worker.h"
#include <QThread>
#include <QDebug>Worker::Worker(QObject *parent): QObject{parent}
{}Worker::~Worker()
{
qDebug()<< __FUNCTION__ << QThread::currentThread();
}void Worker::func1()
{qDebug()<< __FUNCTION__ << QThread::currentThread();
}

使用案例

#ifndef FORM_H
#define FORM_H#include <QWidget>
#include <QThread>
#include <QDebug>#include "worker.h"namespace Ui {
class Form;
}class Form : public QWidget
{Q_OBJECTpublic:explicit Form(QWidget *parent = nullptr);~Form();
signals:void closeThread();private:Ui::Form *ui;
};#endif // FORM_H
#include "form.h"
#include "ui_form.h"Form::Form(QWidget *parent): QWidget(parent), ui(new Ui::Form)
{ui->setupUi(this);//根据亲和性,不应设置为其他线程的成员对象QThread *th = new QThread();Worker *worker = new Worker();qDebug()<< "主线程:" << QThread::currentThread();worker->moveToThread(th);connect(th,&QThread::finished,worker,&Worker::deleteLater);connect(th,&QThread::finished,worker,&QThread::deleteLater);th->start();    //启动子线程worker->func1();    //错误行为connect(ui->pushButton,&QPushButton::clicked,worker,&Worker::func1); //正确线程间通信connect(this,&Form::closeThread,th,&QThread::quit); //关闭线程
}Form::~Form()
{delete ui;emit closeThread();}

总结

使用场景: 线程之间频繁交互的时候(官方推荐)

①禁止行为:禁止直接调用子线程对象接口或者修改数据
因为这会导致跨线程访问问题,可能引发数据竞争、死锁或程序崩溃。
应该通过信号槽连接进行线程间通信。

②独立的事件循环
子线程开启会产生一个独立的事件循环,此时异步线程信号请求会在此次统一处理
不会对发起请求的线程阻塞;

③Qt 的父子对象与线程规则​
​规则 1​:所有 QObject 父子对象必须位于同一线程。
​规则 2​:调用 moveToThread() 会改变对象的线程亲和性(Thread Affinity)。
​冲突点​:如果将一个已移动到子线程的 QObject 设置为另一个线程中对象的子对象,Qt 会触发断言崩溃(如 QObject: Cannot create children for a parent that is in a different thread)。
简单点说既是;A线程中的对象不应该成为B线程的父对象或者子对象

方法3.QRunnable + QThreadPool

#ifndef WORKERTASK_H
#define WORKERTASK_H#include <QRunnable>class WorkerTask : public QRunnable
{
public:WorkerTask();~WorkerTask();
protected:virtual void run();
};#endif // WORKERTASK_H
#include "workertask.h"
#include <QThread>
#include <QDebug>WorkerTask::WorkerTask() {setAutoDelete(true);
}WorkerTask::~WorkerTask()
{
qDebug()<< __FUNCTION__<< QThread::currentThread();
}void WorkerTask::run()
{
qDebug()<< __FUNCTION__<< QThread::currentThread();
}

使用案例

#ifndef FORM1_H
#define FORM1_H#include <QWidget>
#include <QThread>
#include <QDebug>namespace Ui {
class Form1;
}class Form1 : public QWidget
{Q_OBJECTpublic:explicit Form1(QWidget *parent = nullptr);~Form1();private:Ui::Form1 *ui;
};#endif // FORM1_H
#include "form1.h"
#include "ui_form1.h"
#include "workertask.h"
#include <QThreadPool>Form1::Form1(QWidget *parent): QWidget(parent), ui(new Ui::Form1)
{ui->setupUi(this);qDebug()<< "主线程:" << QThread::currentThread();QThreadPool::globalInstance()->start(new WorkerTask());}Form1::~Form1()
{delete ui;
}

总结

场景:适合短生命周期的任务
用完就释放

方法4.快速线程QtConcurrent+QFutureWatcher

其他线程都得创建一堆的对象,管理对象的创建与释放生命周期,
但是QtConcurrent不用,使用QtConcurrent我们可以快速开启一个线程

使用案例

#include "form2.h"
#include "ui_form2.h"
#include <QDebug>
#include <QThread>
#include <QtConcurrent>
#include <QtConcurrent/QtConcurrentMap>Form2::Form2(QWidget *parent): QWidget(parent), ui(new Ui::Form2)
{ui->setupUi(this);qDebug()<< "主线程:" << QThread::currentThread();
}Form2::~Form2()
{delete ui;
}void Form2::on_pushButton_clicked()
{QList<int> list = {1, 2, 3, 4, 5};//通过map开启多个线程执行, 如果使用for每个元素处理是耗时的,但是采用此法可以并行处理// QFuture<void> future = QtConcurrent::map(list, [](int &value) {//     value *= 2; // 将每个元素乘以2//     qDebug()<< __FUNCTION__ << QThread::currentThread();// });QFuture<int> future = QtConcurrent::run([]() -> int {// 计算并返回结果return 42;});qDebug()<< future.result(); //阻塞等待结构
}

绑定监听器,全部执行完则发出fnish信号

QFutureWatcher<void> watcher;
connect(&watcher, &QFutureWatcher<void>::finished, this, []() {qDebug() << "图像处理完成";
});watcher.setFuture(future);

总结

​避免修改共享数据​:尽量使用值传递而非引用传递
​使用轻量级函数​:并行执行的函数应该尽可能轻量
​合理设置线程池大小​:使用 QThreadPool::globalInstance()->setMaxThreadCount()
​处理异常​:确保并行函数不会抛出未捕获的异常

代码下载

链接: 下载

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

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

相关文章

ARM入门学习方法分享

首先认识什么是ARM?ARM公司简介ARM是Advanced RISC Machines的缩写&#xff0c;它是一家微处理器行业的知名企业&#xff0c;该企业设计了大量高性能、廉价、耗能低的RISC &#xff08;精简指令集&#xff09;处理器。 1985年第一个ARM原型在英国剑桥诞生。公司的特点是只设计…

基于springboot的在线数码商城/在线电子产品商品销售系统的设计与实现

用户&#xff1a;数码产品&#xff0c;限时秒杀&#xff0c;种草分享&#xff0c;新品资讯&#xff0c;留言板&#xff0c;订单管理&#xff0c;在线客服&#xff0c;购物车&#xff0c;个人中心管理员&#xff1a;个人中心&#xff0c;用户管理&#xff0c;数码分类管理&#…

Zookeeper学习专栏(十):核心流程剖析之服务启动、请求处理与选举协议

文章目录前言一、服务端启动流程1.1 启动入口类&#xff1a;QuorumPeerMain1.2 集群模式启动核心&#xff1a;runFromConfig1.3 QuorumPeer线程核心逻辑&#xff1a;run()1.4 关键子流程&#xff1a;数据恢复1.5 关键设计要点二、请求处理链&#xff08;责任链模式&#xff09;…

网络基础19--OSPF路由业务多区域

一、OSPF多区域必要性单区域问题&#xff1a;LSDB庞大 → 内存占用高&#xff0c;SPF计算开销大LSA洪泛范围广 → 拓扑变化影响全域无法路由汇总 → 路由表膨胀&#xff0c;查找效率低2. 多区域优势&#xff1a;1. 划分区域&#xff1a;独立LSDB&#xff0c;缩小数据库规模2. 限…

MFC扩展库BCGControlBar Pro v36.2新版亮点:图形管理器等全新升级

BCGControlBar库拥有500多个经过全面设计、测试和充分记录的MFC扩展类。 我们的组件可以轻松地集成到您的应用程序中&#xff0c;并为您节省数百个开发和调试时间。 BCGControlBar专业版 v36.2已全新发布了&#xff0c;在这个版本中添加了一个新的扩展器控件、改进了网格和报表…

QT开发---网络编程上

Qt Network 模块Qt Network 模块提供了丰富的类用于实现各种网络通信功能&#xff0c;涵盖 TCP、UDP、HTTP、FTP 等多种协议。 Qt 网络类均为异步操作&#xff0c;通过信号槽处理结果&#xff0c;避免阻塞 UI 线程。在使用QT进行网络编程之前&#xff0c;就必须在 CMakeLists.t…

[spring6: Mvc-函数式编程]-源码解析

接口 ServerRequest public interface ServerRequest {HttpMethod method();URI uri();UriBuilder uriBuilder();default String path() {return requestPath().pathWithinApplication().value();}default RequestPath requestPath() {return ServletRequestPathUtils.getPar…

Linux DNS 服务器正反向解析

一、环境说明与准备工作 1.基础信息 本次实验用两台 Linux 主机&#xff0c;分别作为 DNS 服务端和客户端&#xff0c;具体信息如下&#xff1a;服务端IP客户端IP网址192.168.120.130192.168.120.128www.zy.com2.准备工作 关闭安全软件&#xff1a;服务端和客户端都要关闭防火墙…

历史数据分析——中证旅游

中证旅游板块走势从月线级别来看2015年5月到2024年9月&#xff0c;月线上走出了一个震荡中枢的月线级别下跌段&#xff1b;目前月线级别底部放巨量&#xff0c;总体还在底部震荡&#xff0c;后续上涨的概率较大。从周线级别来看从2022年12月到2024年9月整体是下跌走势&#xff…

OpHReda精准预测酶最佳PH

1.显著改进&#xff1a;OpHReda通过检索嵌入数据增强机制&#xff0c;显著提高了酶最佳pH预测的准确性&#xff0c;相比现有方法提升了55%的F1分数。2.多尺度残差轻注意力模块&#xff1a;该模块结合了残差学习和多尺度特征提取&#xff0c;增强了模型对酶序列中残差级信息的捕…

醫護行業在未來會被AI淘汰嗎?

隨着AI的迅速發展&#xff0c;似乎所有職業都有被AI替代的風險&#xff0c;那麼醫療領域作為一個高技術依賴性的行業&#xff0c;有機會被淘汰嗎?我們今天就來說說&#xff0c;幾乎不可能被AI淘汰的職業---護理。一) AI在護理中扮演的角色i.) 臨床工作支持1. 健康監測自動化即…

大语言模型加速技术之KV Cache

大语言模型加速技术之KV CacheWhy we need KV Cache &#xff1f;Self-Attention Without CacheSelf-Attention With CacheHuggingface 官方代码实现Why we need KV Cache &#xff1f; 生成式generative模型的推理过程很有特点&#xff0c;我们给一个输入文本&#xff0c;模型…

代码随想录算法训练营第五十三天|图论part4

110.字符串接龙 题目链接&#xff1a;110. 字符串接龙文章讲解&#xff1a;代码随想录思路&#xff1a; 把每个字符串看成图的一个节点。 转换为求无权图两节点的的最短路径。求最短路径用bfs #include <string> #include <vector> #include <iostream> #i…

Java进阶4:泛型、序列化和反序列化

Java泛型 Java泛型是JDK5引入的一个新的特性&#xff0c;泛型提供了编译时的类型安全检测机制&#xff0c;这个机制运行程序员在编译的时候检测到非法的类型。泛型的本质是参数化类型&#xff0c;也就是所操作的数据类型被指定为一个参数。 泛型方法 可以写一个泛型方法&#x…

RAG实战指南 Day 24:上下文构建与提示工程

【RAG实战指南 Day 24】上下文构建与提示工程 文章内容 开篇 欢迎来到"RAG实战指南"系列的第24天&#xff01;今天我们将深入探讨RAG系统中至关重要的上下文构建与提示工程技术。在检索增强生成系统中&#xff0c;如何有效地组织检索到的文档片段&#xff0c;并将…

AWD的攻击和防御手段

一、AWD相关介绍 AWD&#xff08;Attack With Defence&#xff09;是 CTF 线下赛中最接近真实攻防场景、观赏性和对抗性最强的赛制之一。 赛制本质 人人对抗&#xff1a;所有战队互为攻击者与防守者。 零和记分&#xff1a;你拿到的每一分都是别人的失分&#xff0c;总积分恒…

泛微OA8前台SQL注入

漏洞URL&#xff1a; http://106.15.190.147/js/hrm/getdata.jsp?cmdgetSelectAllId&sql***注入点 在getdata.jsp中&#xff0c;直接将request对象交给 weaver.hrm.common.AjaxManager.getData(HttpServletRequest, ServletContext) : 方法处理 在getData方法中&#xff0…

Android 蓝牙学习

在Android中&#xff0c;进行蓝牙设备扫描startDiscovery需要申请位置权限&#xff0c;但有的时候并不需要申请位置权限&#xff0c;就有了android:usesPermissionFlags"neverForLocation"&#xff0c;设置这个就不用申请位置权限来进行蓝牙扫描。 android:usesPerm…

Earth靶机攻略

一.环境准备 1.1Earth靶机环境准备 首先将我们解压好的的Earth.ova放入虚拟机里&#xff0c;并配置环境 将网络连接换成NET连接 二.信息搜集 2.1ip搜集 2.1.1使用netdiscover命令扫描靶机的ip地址,发现地址为192.168.182.137 2.2端口扫描 2.2.1使用nmap工具对目标机进行端…

java8 List常用基本操作(去重,排序,转换等)

参考简述网址: java8 List 根据对象某个字段或多个字段去重、筛选、List转Map、排序、分组、统计计数等等 list简单方法示例如下&#xff1a; 一、先定义一个订单对象&#xff08;Order&#xff09; public class Order {private Long id;private Long userId;private Strin…