Qt多线程技术

Qt提供了许多处理线程的类和函数。下面是Qt程序员可以用来实现多线程应用程序的四种不同方法。

QThread:带有可选事件循环的低级API

QThread是Qt中所有线程控制的基础,每个QThread实例代表并控制一个线程。
QThread既可以被直接实例化,也可以被子类化。实例化QThread提供了一个并行事件循环,允许在次要线程中调用QObject槽。子类化QThread允许应用程序在开始事件循环之前初始化新线程,或者在没有事件循环的情况下运行并行代码。

See the QThread class reference and the threading examples for demonstrations on how to use QThread.

QThreadPool和QRunnable:重用线程

频繁地创建和销毁线程的代价是昂贵的。为了减少这种开销,现有线程可以被新任务重用。QThreadPool是可重用的qthread的集合。

要在QThreadPool的某个线程中运行代码,请重新实现QRunnable::run()并实例化子类QRunnable。使用QThreadPool::start()将QRunnable放入QThreadPool的运行队列中。当线程可用时,QRunnable::run()中的代码将在该线程中执行。

每个Qt应用程序都有一个全局线程池,可以通过QThreadPool::globalInstance()来访问。这个全局线程池根据CPU中的核心数量自动维护最佳线程数量。但是,可以显式地创建和管理一个单独的QThreadPool。

class HelloWorldTask : public QRunnable
{void run() override{qDebug() << "Hello world from thread" << QThread::currentThread();}
};HelloWorldTask *hello = new HelloWorldTask();
// QThreadPool takes ownership and deletes 'hello' automatically
QThreadPool::globalInstance()->start(hello);

Qt Concurrent:使用高级API

Qt Concurrent模块提供了一些高级函数来处理一些常见的并行计算模式:map、filter和reduce。与使用QThread和QRunnable不同,这些函数从来不需要使用诸如互斥量或信号量之类的低级线程原语。相反,它们返回一个QFuture对象,当函数准备好时,该对象可用于检索函数的结果。QFuture还可以用于查询计算进度,暂停/恢复/取消计算。为了方便,QFutureWatcher允许通过信号和插槽与qfuture进行交互

Qt Concurrent的map、filter和reduce算法自动地将计算分布到所有可用的处理器内核上,所以今天编写的应用程序在以后部署到更多内核的系统上时仍然可以扩展。

这个模块还提供了QtConcurrent::run()函数,它可以在另一个线程中运行任何函数。然而,QtConcurrent::run()只支持map、filter和reduce函数可用的功能子集。QFuture可用于获取函数的返回值,并检查线程是否正在运行。但是,对QtConcurrent::run()的调用只使用一个线程,不能被暂停/恢复/取消,也不能查询进度。

有关各个函数的详细信息,请参阅Qt Concurrent模块文档。

QtConcurrent::run:(在另一个线程中运行一个函数。)

// call 'void QImage::invertPixels(InvertMode mode)' in a separate thread
QImage image = ...;
QFuture<void> future = QtConcurrent::run(&image, &QImage::invertPixels, QImage::InvertRgba);
...
future.waitForFinished();
// At this point, the pixels in 'image' have been inverted

Qt Concurrent 支持多种兼容 STL 的容器和迭代器类型,但是最好使用具有随机访问迭代器的 Qt 容器,例如:QList 或 QVector。map 和 filter 函数都接受容器和 begin/end 迭代器。

Concurrent Map 和 Map-Reduce:多线程处理容器里的项

  • QtConcurrent::map():将一个函数应用于一个容器中的每一项,直接修改 items。

  • QtConcurrent::mapped():和 map() 类似,只是它返回一个包含修改内容的新容器。

  • QtConcurrent::mappedReduced():和 mapped() 类似,只是修改后的结果减少或组合成一个单一的结果。

函数模版格式:
U function(T &t);//T必须是容器里的类型,U必须是void(没有返回值和返回类型)例子:
void scale(QImage &image)
{image = image.scaled(100, 100);
}QList<QImage> images = ...;
QFuture<void> future = QtConcurrent::map(images, scale);
函数模版格式:
U function(const T &t);//T必须是容器里的类型,U可以任意类型(最终结果)例子:
QImage scaled(const QImage &image)
{return image.scaled(100, 100);
}QList<QImage> images = ...;//QList里的每张图片都会被缩放
QFuture<QImage> thumbnails = QtConcurrent::mapped(images, scaled);
//多个线程同时运行,每个结果通过QFuture返回。
函数模版:
V必须是void(没有返回值和返回类型),T是mappedReduced后返回的结果(最终结果),U是scaled函数的返回类型。
V function(T &result, const U &intermediate)QImage scaled(const QImage &image)
{return image.scaled(100, 100);
}void addToCollage(QImage &collage, const QImage &thumbnail)
{QPainter p(&collage);static QPoint offset = QPoint(0, 0);p.drawImage(offset, thumbnail);offset += ...;
}QList<QImage> images = ...;
//多个线程同时运算,addToCollage每次只有一个线程调用,所有是线程安全的
QFuture<QImage> collage = QtConcurrent::mappedReduced(images, scaled, addToCollage);
//理解:images对象调用scaled,scaled的结果通过addToCollage的第二个参数传递给addToCollage,addToCollage运算最终结果通过第一个参数返回。

同步模式,直接返回结果:

QList<QImage> images = ...;// Each call blocks until the entire operation is finished.
QList<QImage> future = QtConcurrent::blockingMapped(images, scaled);QtConcurrent::blockingMap(images, scale);QImage collage = QtConcurrent::blockingMappedReduced(images, scaled, addToCollage);

Concurrent Filter 和 Filter-Reduce:对容器里的项过滤后再多线程处理

  • QtConcurrent::filter():对结果进行筛选(根据筛选函数)。

  • QtConcurrent::filtered():和 filter() 类似,只是它返回一个包含过滤内容的新容器。

  • QtConcurrent::filteredReduced():和 filtered() 类似,只是过滤后的结果减少或组合成一个单一的结果。

//T必须匹配存储在序列中的类型。如果应该保留该项,则返回true;如果应该丢弃该项,则返回false。
bool function(const T &t);bool allLowerCase(const QString &string)
{return string.lowered() == string;
}QStringList strings = ...;
//对每一个项的结果都会执行过滤函数判断是否丢弃掉。
QFuture<QString> lowerCaseStrings = QtConcurrent::filtered(strings, allLowerCase);QStringList strings = ...;
QFuture<void> future = QtConcurrent::filter(strings, allLowerCase);
V是void(没有返回值和返回类型),T是最终结果,U是被过滤项目的类型。
V function(T &result, const U &intermediate)void addToDictionary(QSet<QString> &dictionary, const QString &string)
{dictionary.insert(string);
}QStringList strings = ...;
//每个结果都经过addToDictionary筛选,通过第一个参数返回最终结果
//QtConcurrent::filteredReduced()保证一次只有一个线程调用reduce,所以没有必要使用互斥锁来锁定结果变量
QFuture<QSet<QString> > dictionary = QtConcurrent::filteredReduced(strings, allLowerCase, addToDictionary);
  • QFuture:表示异步计算的结果
  • QFutureIterator:允许通过 QFuture 遍历可用的结果

  • QFutureWatcher:允许使用信号槽来监控一个 QFuture

  • QFutureSynchronizer:是一个方便的类,用于一些 QFutures 的自动同步

// Instantiate the objects and connect to the finished signal.
MyClass myObject;
QFutureWatcher<int> watcher;
connect(&watcher, &QFutureWatcher<int>::finished, &myObject, &MyClass::handleFinished);// Start the computation.
QFuture<int> future = QtConcurrent::run(...);
watcher.setFuture(future);
void someFunction()
{QFutureSynchronizer<void> synchronizer;...synchronizer.addFuture(QtConcurrent::run(anotherFunction));synchronizer.addFuture(QtConcurrent::map(list, mapFunction));return; // QFutureSynchronizer waits for all futures to finish
}

WorkerScript: QML中的线程

WorkerScript QML类型允许JavaScript代码与GUI线程并行运行。

每个WorkerScript实例可以附加一个.js脚本。当WorkerScript.sendMessage()被调用时,脚本将在一个单独的线程(和一个单独的QML上下文)中运行。当脚本完成运行时,它可以将应答发送回GUI线程,该线程将调用WorkerScript.onMessage()信号处理程序。

使用WorkerScript类似于使用已移动到另一个线程的worker QObject。数据通过信号在线程之间传输。

有关如何实现脚本的详细信息,以及可以在线程之间传递的数据类型列表,请参阅WorkerScript文档。

选择合适的方案

如上所述,Qt为开发线程应用程序提供了不同的解决方案。给定应用程序的正确解决方案取决于新线程的目的和线程的生命周期。下面是Qt线程技术的比较,然后是一些示例用例的推荐解决方案。

方案的比较

FeatureQThreadQRunnable and QThreadPoolQtConcurrent::run()Qt Concurrent (Map, Filter, Reduce)WorkerScript
语言C++C++C++C++QML
可以指定线程优先级YesYes
线程可以运行事件循环Yes
线程可以通过信号接收数据更新Yes (received by a worker QObject)Yes (received by WorkerScript)
线程可以使用信号来控制Yes (received by QThread)Yes (received by QFutureWatcher)
线程可以通过QFuture来监控PartiallyYes
内置暂停/恢复/取消功能Yes

用例

线程寿命OperationSolution
一次在另一个线程中运行一个新的线性函数,可以选择在运行期间进行进度更新。

Qt提供了不同的解决方案:

  • 将函数放在QThread::run()的重新实现中,并启动QThread。发送信号来更新进度。或
  • 将函数放在QRunnable::run()的重新实现中,并将QRunnable添加到QThreadPool中。写入线程安全的变量以更新进度。或
  • 使用QtConcurrent:: Run()运行函数。写入线程安全的变量以更新进度。
一次在另一个线程中运行现有函数并获取其返回值。使用QtConcurrent:: Run()运行函数。让QFutureWatcher在函数返回时发出finished()信号,并调用QFutureWatcher::result()来获取函数的返回值。
一次对容器的所有项执行操作,使用所有可用的内核。例如,从图像列表生成缩略图。使用QtConcurrent的QtConcurrent::filter()函数选择容器元素,使用QtConcurrent::map()函数对每个元素应用操作。要将输出折叠为单个结果,请使用QtConcurrent::filteredReduced()和QtConcurrent::mappedReduced()。
一次/永久在纯QML应用程序中执行长时间的计算,并在结果准备好时更新GUI。将计算代码放在。js脚本中,并将其附加到WorkerScript实例。调用WorkerScript.sendMessage()在新线程中开始计算。让脚本也调用sendMessage(),将结果传递回GUI线程。在onMessage中处理结果并更新GUI。
永久让一个对象驻留在另一个线程中,该线程可以根据请求执行不同的任务和/或可以接收新数据来处理。子类化一个QObject来创建一个worker。实例化这个worker对象和一个QThread。将工作线程移动到新线程。通过排队信号槽连接向工作对象发送命令或数据。
永久在另一个线程中重复执行昂贵的操作,其中线程不需要接收任何信号或事件。直接在QThread::run()的重新实现中编写无限循环。启动不使用事件循环的线程。让线程发出信号,将数据发送回GUI线程。

Thread Support in Qt | Qt 5.15

Multithreading Technologies in Qt | Qt 5.15

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

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

相关文章

连接Huggingface报requests.exceptions.SSLError错误

最近在学习使用 SHAP 算法解释 BERT 模型的输出结果&#xff0c;然而在从 Huggingface 上导入模型和数据集的过程中出现了网络连接相关的错误&#xff0c;本文用于记录错误类型和解决错误的方法。 1 代码示例 SHAP 官方展示的代码如下&#xff1a; import datasets import nu…

Linux screen命令使用

文章目录 1. 前言2. screen是什么?3. screen使用场景描述3. screen常用命令4. 小结5. 参考 1. 前言 实际开发中用到的云服务器&#xff0c;如果项目使用的是python&#xff0c;需要利用项目运行一些时间较长的项目程序脚本的话&#xff0c;由于我们通过ssh连接远端服务器&…

一文详解扩散模型

文章目录 1、常见的生成模型2、变分推断简介3、文生图的评价指标4、Diffusion Models5、其他技术交流群精选 节前&#xff0c;我们星球组织了一场算法岗技术&面试讨论会&#xff0c;邀请了一些互联网大厂朋友、参加社招和校招面试的同学。 针对算法岗技术趋势、大模型落地…

软设之进度管理之pert图

pert图 优点: 不仅给出了各个任务的开始时间&#xff0c;结束时间和完成该任务所需的时间&#xff0c;还给出了任务之间的关系&#xff0c;即哪些任务完成之后才能开始另外一些任务&#xff0c;以及如期完成整个工程的关键路径。松弛时间反映了某些任务是可以推迟其开始时间或…

2024年通信安全员ABC证证考试题库及通信安全员ABC证试题解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年通信安全员ABC证证考试题库及通信安全员ABC证试题解析是安全生产模拟考试一点通结合&#xff08;安监局&#xff09;特种作业人员操作证考试大纲和&#xff08;质检局&#xff09;特种设备作业人员上岗证考试大…

Spring Boot 开发 -- 常用加密算法简介(一)

在Spring Boot开发过程中&#xff0c;安全性始终是一个重要的考量因素。数据加密作为保护数据安全的一种有效手段&#xff0c;被广泛应用于各种应用场景中。本文将介绍几种在Spring Boot开发中常用的加密算法&#xff0c;并探讨它们的应用场景。 一、 对称加密算法 对称加密算…

项目3:从0开始的RPC框架(扩展版)-3

七. 负载均衡 1. 需求分析 目前我们的RPC框架仅允许消费者读取第一个服务提供者的服务节点&#xff0c;但在实际应用中&#xff0c;同一个服务会有多个服务提供者上传节点信息。如果消费者只读取第一个&#xff0c;势必会增大单个节点的压力&#xff0c;并且也浪费了其它节点…

Jenkins+K8s实现持续集成(一)

镜像仓库的搭建 docker run -d \--restartalways \--name registry \-p 5000:5000 \-v /root/devops/registry/data:/var/lib/registry \registry安装完之后&#xff0c;执行下面命令可以看到镜像仓库已经安装成功 docker ps 然后在浏览器上输入下面地址进行访问 http://ip:…

车牌号识别(低级版)

import cv2 from matplotlib import pyplot as plt import os import numpy as np from paddleocr import PaddleOCR, draw_ocr from PIL import Image, ImageDraw, ImageFont# 利用paddelOCR进行文字扫描&#xff0c;并输出结果 def text_scan(img_path):ocr PaddleOCR(use_a…

HTML(11)——CSS三大特性

CSS拥有三大特性&#xff0c;分别是&#xff1a;继承性&#xff0c;层叠性&#xff0c;优先级 继承性 说明&#xff1a;子级标签默认继承父级标签的文字控制属性。 如果子级自己有样式&#xff0c;则父级的属性不生效 例如&#xff1a; <style> body{ font-size:30px;…

C++之结构体初始化使用总结

1、前言 结构体是常用的自定义构造类型&#xff0c;是一种很常见的数据打包方法。如下所示为一典型的包含各种数据类型结构体Mystruct。其包括double、float、int、bool、vector<int>、char数据类型。因此&#xff0c;合理利用结构体&#xff0c;可以有效对数据进行组织&…

ADS1220芯片写寄存器失败

1&#xff09;场景&#xff1a;最近调试ADS1220 的芯片&#xff0c;需要读取不同通道的AD值&#xff0c;修改寄存器0的值时一直失败 但是在单片机启动时&#xff0c;写寄存器0时&#xff0c;值能正确写入&#xff0c;并正确读出&#xff0c;之后写完读取出的都是FF或其他异常值…

LIO-SAM调试记录

一、调试环境 室内环境。利用激光数据和imu数据进行建图&#xff0c;没有用gps数据。 二、调试问题 问题一&#xff1a; map坐标系和base_link坐标系一开始不重合。 解决方法&#xff1a; 将param.yaml文件中的useImuHeadingInitialization设置为false。 问题二&#xff1…

CobaltStrike后渗透进阶篇

0x01 网络钓鱼攻击 钓鱼攻击简介 钓鱼攻击主要通过生成的木马诱使受害者运行后上线&#xff0c;其中木马一般都伪装成正常的程序。与此同时配合钓鱼网站可帮助攻击者模拟真实网站诱骗受害者访问&#xff0c;达到获取账号密码、上线木马等目的。接下来主要介绍后门程序的生成及…

利用Python爬取天气数据并实现数据可视化,一个完整的Python项目案例讲解

要使用Python爬取天气数据并进行制图分析分几个步骤进行&#xff1a; 选择数据源&#xff1a;首先&#xff0c;你需要找到一个提供天气数据的API或网站。一些常见的选择包括&#xff1a;OpenWeatherMap、Weatherbit、Weather Underground等。 安装必要的库&#xff1a;你需要安…

mamba模型原理解读

本文主要讲解我对于2023年提出的mamba模型的理解和解读&#xff0c;mamba模型的提出为transformer模型存在的计算效率低下&#xff0c;需要大量时间运行程序提出了解决方案。提高了模型的运行效率和计算效率。我主要是根据下面这篇文章入手&#xff1a; 1.mamba模型是通过堆叠多…

SpringBoot调用WebService的实践

作者所在公司的系统间的信息交互是通过webservice完成。如&#xff1a;MES与SAP的交互&#xff0c;MES与WMS的交换&#xff0c;MES与SRM的交互&#xff0c;MES与IOT的交互等。 MES是用.NET VS2008 C#写的&#xff0c;调用webservice很简单&#xff0c;这里不再赘述。如有想了解…

kotlin数组

1、kotlin中的数组与java数组比较&#xff1a; 2、创建 fun main() {// 值创建val a intArrayOf(1,2,3)// 表达式创建val b IntArray(3){println("it: ${it}")it1}println("a数组&#xff1a;${a.contentToString()}, 长度&#xff1a;${a.size}")prin…

重生之 SpringBoot3 入门保姆级学习(22、场景整合 Swagger 接口文档)

重生之 SpringBoot3 入门保姆级学习&#xff08;22、场景整合 Swagger 接口文档&#xff09; 6.2 Swagger 接口文档 6.2 Swagger 接口文档 1、将 starter 导入 Maven 官网 https://springdoc.org/<dependency><groupId>org.springdoc</groupId><artifact…

电路分析期末总结笔记下

对称三相电路的线电流和相电流&#xff0c;线电压和相电压关系 相电压与线电压的关系 线电压定义&#xff1a;任意两相之间的电压称为线电压&#xff0c;常用符号V_L表示。 相电压定义&#xff1a;一相绕组两端的电压称为相电压&#xff0c;常用符号V_P表示。 关系&#xff1…