Qt中的多线程技术

简介: 简述Qt 提供了许多类和函数来处理线程,下面我们总结下可以用来实现多线程应用程序的四种不同方式。简述QThread - 具有可选事件循环的低级 APIQThreadPool 和 QRunnable - 重用线程Qt Concurrent - 使用高级 APIWorkerScript - QML 中的线程选择适当的方法解决方案的比较示例用例

简述

Qt 提供了许多类和函数来处理线程,下面我们总结下可以用来实现多线程应用程序的四种不同方式。

QThread - 具有可选事件循环的低级 API

QThread 是 Qt 中所有线程控制的基础,每个 QThread 实例表示和控制一个线程。

QThread 可以直接实例化或子类,实例化 QThread 提供了一个并行事件循环,允许在次线程中调用 QObject 的槽函数。子类化 QThread 允许应用程序在开始其事件循环之前初始化新的线程,或者运行没有事件循环的并行代码。

有关如何使用 QThread 的演示,请参阅 QThread 类参考和线程示例。

QThreadPool 和 QRunnable - 重用线程

经常创建和销毁线程可能是昂贵的,为了减少这种开销,现有线程可以重新用于新任务。QThreadPool 是可重用的 QThreads 的集合。

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

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

Qt Concurrent - 使用高级 API

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

Qt Concurrent 的 map、filter 和 reduce 算法在所有可用的处理器核心之间自动分配计算,因此今天编写的应用程序将在以后在具有更多核心的系统上部署时继续扩展。

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

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

WorkerScript - QML 中的线程

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

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

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

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

选择适当的方法

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

解决方案的比较

特性 QThread QRunnable 和 QThreadPool QtConcurrent::run() Qt Concurrent (Map, Filter, Reduce) WorkerScript
语言 C++ C++ C++ C++ QML
可以指定线程优先级
线程可以运行事件循环
线程可以通过信号接收数据更新 是(由 worker QObject 接收) 是(由 WorkerScript 接收)
线程可以使用信号控制 是(由 QThread 接收) 是(由 QFutureWatcher 接收)
线程可以通过 QFuture 监视 部分
内置的暂停/恢复/取消功能

示例用例

生命周期 操作 解决方案
一次调用 在另一个线程中运行一个新的线性函数,可选择在运行过程中更新进度。 Qt 提供了不同的解决方案:
1. 将函数放在 QThread::run() 的重新实现中,并启动 QThread,发射信号来更新进度。
2. 将函数放在 QRunnable::run() 的重新实现中,并将 QRunnable 添加到 QThreadPool,写入线程安全的变量来更新进度。
3. 使用 QtConcurrent::run() 运行函数,写入线程安全的变量来更新进度。
一次调用 在另一个线程中运行现有函数并获取其返回值 使用 QtConcurrent::run() 运行函数,当函数返回时,有一个 QFutureWatcher 发出 finished() 信号,并调用 QFutureWatcher::result() 获取函数的返回值。
一次调用 使用所有可用内核对容器的所每一项执行操作。例如,从图像列表中生成缩略图。 使用 Qt Concurrent 的 QtConcurrent::filter() 函数来选择容器元素,并使用 QtConcurrent::map() 函数来对每个元素应用一个操作。若要将输出折叠成单一的结果,改用 QtConcurrent::filteredReduced() 和QtConcurrent::mappedReduced() 来代替。
一次调用/持久运行 在纯 QML 应用程序中执行长计算,并在结果准备好时更新 GUI。 将计算代码放在 .js 脚本中,并将其附加到 WorkerScript 实例。调用 sendMessage() 在一个新的线程中启动计算,也让脚本调用 WorkerScript::sendMessage(),将结果传递给 GUI 线程,处理 onMessage 中的结果并更新 GUI。
持久运行 有一个对象生活在另一个线程中,可以根据请求执行不同的任务和/或可以接收新的数据。 子类化一个 QObject 以创建 worker。实例化这个 worker 对象和一个 QThread,将 worker 移动到新线程,通过 queued 信号槽连接将命令或数据发送到 worker 对象。
持久运行 在另一个线程中重复执行昂贵的操作,其中线程不需要接收任何信号或事件。 在 QThread::run() 的重新实现中直接编写无限循环,启动没有事件循环的线程,让线程发出信号将数据发送回 GUI 线程。
目录
相关文章
|
2月前
|
NoSQL 数据处理 调度
【Redis深度专题】「踩坑技术提升」探索Redis 6.0为何必须启用多线程以提升性能与效率
【Redis深度专题】「踩坑技术提升」探索Redis 6.0为何必须启用多线程以提升性能与效率
250 0
|
6天前
|
存储 缓存 前端开发
Java串口通信技术探究3:RXTX库线程 优化系统性能的SerialPortEventListener类
Java串口通信技术探究3:RXTX库线程 优化系统性能的SerialPortEventListener类
25 3
|
8天前
|
Dart 前端开发 安全
【Flutter前端技术开发专栏】Flutter中的线程与并发编程实践
【4月更文挑战第30天】本文探讨了Flutter中线程管理和并发编程的关键性,强调其对应用性能和用户体验的影响。Dart语言提供了`async`、`await`、`Stream`和`Future`等原生异步支持。Flutter采用事件驱动的单线程模型,通过`Isolate`实现线程隔离。实践中,可利用`async/await`、`StreamBuilder`和`Isolate`处理异步任务,同时注意线程安全和性能调优。参考文献包括Dart异步编程、Flutter线程模型和DevTools文档。
【Flutter前端技术开发专栏】Flutter中的线程与并发编程实践
|
14天前
|
缓存 Java 编译器
第一章 Java线程池技术应用
第一章 Java线程池技术应用
18 0
|
14天前
|
并行计算 算法 安全
Java从入门到精通:2.1.3深入学习Java核心技术——掌握Java多线程编程
Java从入门到精通:2.1.3深入学习Java核心技术——掌握Java多线程编程
|
15天前
|
并行计算 算法 Java
Java中的多线程技术实现与应用
【4月更文挑战第23天】本文将深入探讨Java中的多线程技术,包括其基本概念、实现方法以及在实际应用中的优势。我们将通过实例代码和应用场景,详细解析多线程技术在Java中的应用,以期帮助读者更好地理解和掌握这一技术。
|
17天前
|
Java
Java中的多线程技术实现
【4月更文挑战第22天】本文将深入探讨Java中的多线程技术实现,包括线程的创建、启动、同步和通信等方面。通过实例分析,我们将了解如何利用多线程提高程序的性能和效率。
9 2
|
19天前
|
Java
Java中的多线程技术实现
【4月更文挑战第20天】本文主要介绍了Java中的多线程技术实现,包括线程的创建、启动、同步和通信等方面。通过详细的代码示例和解析,帮助读者深入理解Java多线程技术的原理和应用。
|
1月前
|
Java API 调度
Java中的并发编程:探索多线程技术的奥秘
Java作为一种高度并发的编程语言,其多线程技术一直备受关注。本文将深入探讨Java中的并发编程,从基本概念到高级应用,解析多线程技术的奥秘,帮助读者更好地理解和应用Java中的并发编程。
|
2月前
|
程序员 开发者 Python
Python中的并发编程与多线程技术探究
Python作为一种流行的编程语言,其在并发编程方面有着独特的特点和强大的功能。本文将深入探讨Python中的并发编程技术,重点介绍多线程技术在Python中的应用与实现方式,以及如何利用多线程提高程序的性能和效率。