QT异步线程通信

在使用 QThreadPool 提交任务后,如果你需要知道任务何时完成,并且需要使用任务的执行结果,可以通过以下几种方式来实现:

1. 使用信号和槽

QRunnable 提供了一个 finished() 信号,当任务执行完成后会发出。你可以在任务完成后通过信号和槽机制通知主线程。

示例代码
#include <QCoreApplication>
#include <QThreadPool>
#include <QRunnable>
#include <QDebug>
#include <QThread>class Worker : public QRunnable {
public:Worker() {// 连接 finished 信号到自定义槽connect(this, &Worker::finished, this, &Worker::onFinished);}void run() override {qDebug() << "Worker running in thread" << QThread::currentThreadId();// 模拟耗时任务QThread::sleep(3);qDebug() << "Worker finished";emit finished(); // 发出任务完成信号}private slots:void onFinished() {qDebug() << "Worker finished in thread" << QThread::currentThreadId();// 在这里可以处理任务完成后的逻辑}
};int main(int argc, char *argv[]) {QCoreApplication app(argc, argv);// 获取全局线程池QThreadPool* globalThreadPool = QThreadPool::globalInstance();// 创建一个任务Worker* worker = new Worker();// 将任务添加到全局线程池qDebug() << "Starting worker in main thread" << QThread::currentThreadId();globalThreadPool->start(worker);// 主线程继续运行qDebug() << "Main thread continues running immediately";QThread::sleep(1); // 等待一段时间,观察输出qDebug() << "Main thread still running";return app.exec();
}

输出示例

Starting worker in main thread 0x1234
Main thread continues running immediately
Main thread still running
Worker running in thread 0x5678
Worker finished
Worker finished in thread 0x5678

2. 使用 QFutureQtConcurrent::run

如果你需要更灵活的异步任务管理,可以使用 QtConcurrent::run,它会返回一个 QFuture 对象,你可以通过它来检查任务的状态或获取任务的返回值。

示例代码
#include <QCoreApplication>
#include <QtConcurrent>
#include <QDebug>
#include <QThread>
#include <QFuture>
#include <QFutureWatcher>int workerFunction() {qDebug() << "Worker running in thread" << QThread::currentThreadId();// 模拟耗时任务QThread::sleep(3);qDebug() << "Worker finished";return 42; // 返回结果
}int main(int argc, char *argv[]) {QCoreApplication app(argc, argv);// 使用 QtConcurrent::run 提交任务QFuture<int> future = QtConcurrent::run(workerFunction);// 主线程继续运行qDebug() << "Main thread continues running immediately";QThread::sleep(1); // 等待一段时间,观察输出qDebug() << "Main thread still running";// 等待任务完成并获取结果qDebug() << "Waiting for worker to finish...";int result = future.result(); // 阻塞主线程,直到任务完成qDebug() << "Worker result:" << result;return app.exec();
}

输出示例

Main thread continues running immediately
Main thread still running
Worker running in thread 0x5678
Worker finished
Waiting for worker to finish...
Worker result: 42

3. 使用 QThreadPool::waitForDone()

如果你需要等待所有任务完成,可以使用 QThreadPool::waitForDone() 方法。这个方法会阻塞当前线程,直到线程池中的所有任务都完成。

示例代码
#include <QCoreApplication>
#include <QThreadPool>
#include <QRunnable>
#include <QDebug>
#include <QThread>class Worker : public QRunnable {
public:void run() override {qDebug() << "Worker running in thread" << QThread::currentThreadId();// 模拟耗时任务QThread::sleep(3);qDebug() << "Worker finished";}
};int main(int argc, char *argv[]) {QCoreApplication app(argc, argv);// 获取全局线程池QThreadPool* globalThreadPool = QThreadPool::globalInstance();// 创建一个任务Worker* worker = new Worker();// 将任务添加到全局线程池qDebug() << "Starting worker in main thread" << QThread::currentThreadId();globalThreadPool->start(worker);// 主线程继续运行qDebug() << "Main thread continues running immediately";QThread::sleep(1); // 等待一段时间,观察输出qDebug() << "Main thread still running";// 等待所有任务完成qDebug() << "Waiting for all tasks to finish...";globalThreadPool->waitForDone();qDebug() << "All tasks finished";return app.exec();
}

输出示例

Starting worker in main thread 0x1234
Main thread continues running immediately
Main thread still running
Worker running in thread 0x5678
Worker finished
Waiting for all tasks to finish...
All tasks finished

总结

  • 信号和槽:通过 QRunnable::finished 信号通知任务完成。
  • QFutureQtConcurrent::run:提供更灵活的异步任务管理,可以获取任务的返回值。
  • QThreadPool::waitForDone:等待线程池中的所有任务完成,但会阻塞当前线程。

根据你的需求选择合适的方法。如果你需要任务的返回值,建议使用 QtConcurrent::runQFuture


QtConcurrent::run 和直接使用 QThread 在功能和使用方式上有显著的区别。以下是它们的主要区别:

1. 使用方式

  • QtConcurrent::run

    • 更简单QtConcurrent::run 是一个高级接口,用于简化异步任务的提交和管理。它返回一个 QFuture 对象,可以用来检查任务的状态或获取任务的返回值。
    • 无需手动管理线程:你只需要提供一个函数或 lambda 表达式,QtConcurrent::run 会自动将任务提交到线程池中执行,无需手动创建和管理 QThread
    • 支持返回值QFuture 可以存储任务的返回值,方便在任务完成后获取结果。
  • QThread

    • 更灵活QThread 是一个低级接口,提供了对线程的细粒度控制。你可以创建自己的线程类,管理线程的启动、停止和同步。
    • 需要手动管理线程:你需要手动创建线程,连接信号和槽,管理线程的生命周期。
    • 不直接支持返回值:线程的执行结果需要通过信号和槽或其他机制传递回主线程。

2. 线程管理

  • QtConcurrent::run

    • 使用线程池QtConcurrent::run 内部使用 QThreadPool 来管理线程。任务会被提交到全局线程池中,由线程池负责分配线程。这种方式可以减少线程创建和销毁的开销,提高性能。
    • 自动管理线程生命周期:任务完成后,线程会自动返回线程池,无需手动管理。
  • QThread

    • 手动管理线程:你需要手动创建和启动线程,并在任务完成后手动停止线程。
    • 线程生命周期:线程的生命周期由你控制,需要确保线程在任务完成后正确退出。

3. 任务状态和结果

  • QtConcurrent::run

    • QFuture 提供状态检查QFuture 提供了多种方法来检查任务的状态,例如:
      • isFinished():检查任务是否完成。
      • isRunning():检查任务是否正在运行。
      • result():获取任务的返回值。
    • 支持异步操作QFuture 可以与 QFutureWatcher 配合使用,通过信号和槽机制在任务完成时通知主线程。
  • QThread

    • 手动检查状态:你需要通过信号和槽机制或手动检查线程的状态。
    • 不直接支持返回值:线程的执行结果需要通过信号和槽或其他机制传递回主线程。

4. 适用场景

  • QtConcurrent::run

    • 简单任务:适用于简单的异步任务,特别是那些不需要复杂线程管理的场景。
    • 任务结果处理:当你需要获取任务的返回值时,QFuture 提供了方便的接口。
  • QThread

    • 复杂任务:适用于需要更细粒度控制线程的复杂任务。
    • 长时间运行的任务:适用于需要长时间运行的后台任务,例如网络通信、文件处理等。

示例对比

使用 QtConcurrent::run
#include <QCoreApplication>
#include <QtConcurrent>
#include <QDebug>
#include <QThread>int workerFunction() {qDebug() << "Worker running in thread" << QThread::currentThreadId();QThread::sleep(3);qDebug() << "Worker finished";return 42; // 返回结果
}int main(int argc, char *argv[]) {QCoreApplication app(argc, argv);// 提交任务QFuture<int> future = QtConcurrent::run(workerFunction);// 主线程继续运行qDebug() << "Main thread continues running immediately";QThread::sleep(1);// 等待任务完成并获取结果qDebug() << "Waiting for worker to finish...";int result = future.result();qDebug() << "Worker result:" << result;return app.exec();
}
使用 QThread
#include <QCoreApplication>
#include <QThread>
#include <QDebug>
#include <QMutex>
#include <QWaitCondition>class Worker : public QObject {Q_OBJECT
public:Worker() : result(0), finished(false) {}void run() {qDebug() << "Worker running in thread" << QThread::currentThreadId();QThread::sleep(3);result = 42; // 设置结果finished = true; // 标记任务完成condition.wakeOne(); // 通知主线程}int getResult() const { return result; }bool isFinished() const { return finished; }signals:void finished();private:mutable QMutex mutex;QWaitCondition condition;int result;bool finished;
};int main(int argc, char *argv[]) {QCoreApplication app(argc, argv);Worker worker;QThread thread;worker.moveToThread(&thread);QObject::connect(&thread, &QThread::started, &worker, &Worker::run);thread.start();qDebug() << "Main thread continues running immediately";QThread::sleep(1);// 等待任务完成qDebug() << "Waiting for worker to finish...";QMutexLocker locker(&worker.mutex);while (!worker.isFinished()) {worker.condition.wait(&locker);}int result = worker.getResult();qDebug() << "Worker result:" << result;thread.quit();thread.wait();return app.exec();
}

总结

  • QtConcurrent::run

    • 优点:简单易用,自动管理线程,支持返回值。
    • 缺点:功能相对有限,适合简单任务。
    • 适用场景:适合简单的异步任务,特别是需要获取任务结果的场景。
  • QThread

    • 优点:功能强大,支持复杂的线程管理。
    • 缺点:使用复杂,需要手动管理线程。
    • 适用场景:适合需要细粒度控制线程的复杂任务。

根据你的需求选择合适的方式。如果你的任务简单且需要返回值,推荐使用 QtConcurrent::run。如果你的任务复杂且需要更细粒度的线程管理,推荐使用 QThread


在 Qt 中,QFuture 是一个线程安全的对象,用于表示异步操作的结果。当你将 QFuture 作为值传递给其他函数时,实际上传递的是一个轻量级的“未来”对象的副本。这个副本与原始的 QFuture 对象共享底层的异步操作状态。

关键点

  • 共享状态:尽管 QFuture 是按值传递的,但它内部维护的是一个共享的状态。这意味着,无论你传递了多少个副本,它们都会指向同一个底层的异步操作状态。
  • 线程安全QFuture 的状态是线程安全的,因此你可以在多个线程中安全地访问和修改它的状态。

示例

假设你有以下代码:

void MachineFileBrowser::handleSingleClick(const QModelIndex &index)
{if (index.isValid() && lastClickedIndex == index){QString path = model->getFilePath(index);fileloadFuture = QtConcurrent::run([this, path]() {MachineTree &tempTree = currentTemplate->getMachineTree();tempTree = MachineTree::parseFromTarXmlFile(path);  // 解析机器树数据});emit itemReClicked(index, fileloadFuture);} else{lastClickedIndex = index;}
}

itemReClicked 信号的槽函数中,你可以这样处理:

void SomeClass::handleItemReClicked(const QModelIndex &index, QFuture<void> future)
{// 检查任务是否完成if (future.isFinished()){qDebug() << "Task is finished";}else{qDebug() << "Task is still running";}
}

关键点解释

  1. fileloadFuture 的状态

    • fileloadFuture 是一个 QFuture<void> 对象,它表示一个异步操作的未来结果。
    • 当你将 fileloadFuture 传递给 itemReClicked 信号时,传递的是一个副本,但这个副本与原始的 fileloadFuture 共享底层的状态。
  2. 状态同步

    • 无论你在哪个地方访问 fileloadFuture,它的状态(例如 isFinished())始终是同步的。这是因为 QFuture 内部使用了共享的状态机制。
    • 这意味着,即使你在多个地方持有 fileloadFuture 的副本,它们的状态始终是一致的。

示例代码

假设你有一个槽函数 handleItemReClicked,它接收 fileloadFuture 的副本:

void SomeClass::handleItemReClicked(const QModelIndex &index, QFuture<void> future)
{// 检查任务是否完成if (future.isFinished()){qDebug() << "Task is finished";}else{qDebug() << "Task is still running";}
}

handleSingleClick 中,你发射了 itemReClicked 信号:

emit itemReClicked(index, fileloadFuture);

在槽函数中,你可以通过 future.isFinished() 检查任务是否完成。无论任务是否完成,future.isFinished() 的结果始终是正确的,因为 QFuture 的状态是共享的。

总结

  • QFuture 的状态是共享的:即使你将 QFuture 作为值传递,它的状态仍然是共享的。
  • 线程安全QFuture 的状态是线程安全的,你可以在多个线程中安全地访问和修改它的状态。
  • 状态同步:无论你在哪个地方访问 QFuture,它的状态始终是一致的。

因此,即使 fileloadFuture 是按值传递的,你仍然可以在其他函数中通过 isFinished() 检查任务的状态,并且结果始终是正确的。

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

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

相关文章

利用并行处理提高LabVIEW程序执行速度

在 LabVIEW 编程中&#xff0c;提升程序执行速度是优化系统性能的关键&#xff0c;而并行处理技术则是实现这一目标的有力武器。通过合理运用并行处理&#xff0c;不仅能加快程序运行&#xff0c;还能增强系统的稳定性和响应能力。下面将结合实际案例&#xff0c;深入探讨如何利…

机器学习第三讲:监督学习 → 带答案的学习册,如预测房价时需要历史价格数据

机器学习第三讲&#xff1a;监督学习 → 带答案的学习册&#xff0c;如预测房价时需要历史价格数据 资料取自《零基础学机器学习》。 查看总目录&#xff1a;学习大纲 关于DeepSeek本地部署指南可以看下我之前写的文章&#xff1a;DeepSeek R1本地与线上满血版部署&#xff1…

Open CASCADE学习|实现裁剪操作

1. 引言 Open CASCADE (简称OCC) 是一个功能强大的开源几何建模内核&#xff0c;广泛应用于CAD/CAM/CAE领域。裁剪操作作为几何建模中的基础功能&#xff0c;在模型编辑、布尔运算、几何分析等方面有着重要作用。本文将全面探讨Open CASCADE中的裁剪操作实现原理、应用场景及具…

【redis】分片方案

Redis分片&#xff08;Sharding&#xff09;是解决单机性能瓶颈的核心技术&#xff0c;其本质是将数据分散存储到多个Redis节点&#xff08;实例&#xff09;中&#xff0c;每个实例将只是所有键的一个子集&#xff0c;通过水平扩展提升系统容量和性能。 分片的核心价值 性能提…

RGB矩阵照明系统详解及WS2812配置指南

RGB矩阵照明系统详解及WS2812配置指南 一、RGB矩阵照明简介 RGB矩阵照明是一种强大的功能&#xff0c;允许使用外部驱动器驱动的RGB LED矩阵为键盘增添绚丽的灯光效果。该系统与RGBLIGHT功能无缝集成&#xff0c;因此您可以使用与RGBLIGHT相同的键码来控制它&#xff0c;操作…

[250509] x-cmd 发布 v0.5.11 beta:x ping 优化、AI 模型新增支持和语言变量调整

目录 X-CMD 发布 v0.5.11 beta&#x1f4c3;Changelog&#x1f9e9; ping&#x1f9e9; openai&#x1f9e9; gemini&#x1f9e9; asdf&#x1f9e9; mac✅ 升级指南 X-CMD 发布 v0.5.11 beta &#x1f4c3;Changelog &#x1f9e9; ping 调整 x ping 默认参数为 bing.com&a…

嵌入式开发学习日志Day17

第十一章 结构体与共用体 一、结构体 1、结构体 一般形式 【struct 标识符】 结构体中的标识符一般首字母大写&#xff1b; 【.】结构体成员运算符&#xff1b; 优先级 1 级 结合方向&#xff1a;从左至右&#xff1b; 【->】:指向结构体成员运算符&#x…

发那科机器人5(异常事件和程序备份加载+ROBOGUIDE离线仿真)

发那科机器人5(异常事件和程序备份加载+ROBOGUIDE离线仿真) 一,异常事件和程序备份加载1,常见异常事件2,零点复归介绍3,程序备份-加载(未整理)二,`ROBOGUIDE`离线仿真1,仿真软件简介及安装步骤(未整理)2,机器人==导入与工具==与==工件添加==2.1,机器人导入(未整…

青少年编程与数学 02-019 Rust 编程基础 01课题、环境准备

青少年编程与数学 02-019 Rust 编程基础 01课题、环境准备 一、Rust核心特性应用场景开发工具社区与生态 二、Rust 和 Python 比较1. **内存安全与并发编程**2. **性能**3. **零成本抽象**4. **跨平台支持**5. **社区与生态系统**6. **错误处理**7. **安全性**适用场景总结 三、…

Java反射 八股版

目录 一、核心概念阐释 1. Class类 2. Constructor类 3. Method类 4. Field类 二、典型应用场景 1. 框架开发 2. 单元测试 3. JSON序列化/反序列化 三、性能考量 四、安全与访问控制 1. 安全管理器限制 2. 打破封装性 3. 安全风险 五、版本兼容性问题 六、最佳…

操作系统的初步了解

目录 引言&#xff1a;什么是操作系统&#xff1f; 一、设计操作系统的目的 二、操作系统是做什么的&#xff1a; 操作系统主要有四大核心任务&#xff1a; 1. 管理硬件 2. 运行软件 3. 存储数据 4. 提供用户界面 如何理解操作系统的管理呢&#xff1f; 1. 什么是操作…

Mkdocs页面如何嵌入PDF

嵌入PDF 嵌入PDF代码 &#xff0c;注意PDF的相对地址 <iframe src"../个人简历.pdf (相对地址)" width"100%" height"800px" style"border: 1px solid #ccc; overflow: auto;"></iframe>我的完整代码&#xff1a; <d…

链表结构深度解析:从单向无头到双向循环的实现全指南

上篇博客实现动态顺序表时&#xff0c;我们会发现它存在许多弊端&#xff0c;如&#xff1a; • 中间/头部的插⼊删除&#xff0c;时间复杂度为O(N) • 增容需要申请新空间&#xff0c;拷⻉数据&#xff0c;释放旧空间。会有不⼩的消耗。 • 增容⼀般是呈2倍的增⻓&#xff0c;…

@PostConstruct @PreDestroy

PostConstruct 是 Java EE&#xff08;现 Jakarta EE&#xff09;中的一个注解&#xff0c;用于标记一个方法在对象初始化完成后立即执行。它在 Spring 框架、Java Web 应用等场景中广泛使用&#xff0c;主要用于资源初始化、依赖注入完成后的配置等操作。 1. 基本作用 执行时…

【ArcGIS微课1000例】0146:将多个文件夹下的影像移动到一个目标文件夹(以Landscan数据为例)

本文讲述将多个文件夹下的影像移动到一个目标文件夹,便于投影变换、裁剪等操作。 文章目录 一、数据准备二、解压操作三、批量移动四、查看效果五、ArcGIS操作一、数据准备 全球人口数据集Landscan2000-2023如下所示,每年数据位一个压缩包: 二、解压操作 首先将其解压,方…

专业级 GIF 制作工具深度解析:Gifski 与 GIPHY CAPTURE 的技术对比与实战指南

《Gifski 与 GIPHY CAPTURE&#xff1a;GIF 制作工具的深度对比与实战应用》 最近在尝试做一些培训文档&#xff0c;需要使用GIF图做动态效果&#xff0c;把工具选型过程给大家做一下分享。 先看一张对比表&#xff0c;具体如下&#xff1a; 场景 Windows macOS Linux 移…

selenium替代----playwright

安装 好处特点&#xff1a;这个东西不像selenium需要固定版本的驱动 pip config set global.index-url https://mirrors.aliyun.com/pypi/simplepip install --upgrade pippip install playwright playwright installplaywright install ffmpeg (处理音视频的)验证&#x…

Python代码编程基础

字符串 str.[]实现根据下标定位实现对元素的截取 for 循环可以实现遍历 while 循环可以在实现遍历的同时实现对某一下标数值的修改 字符串前加 r 可以实现对字符串的完整内容输出 字符串前加 f 可以实现对字符串内{}中包裹内容的格式化输出&#xff0c;仅在 v3.6 之后可用…

5月9号.

v-for: v-bind: v-if&v-show: v-model: v-on: Ajax: Axios: async&await: Vue生命周期: Maven: Maven坐标:

Spring 必会之微服务篇(1)

目录 引入 单体架构 集群和分布式架构 微服务架构 挑战 Spring Cloud 介绍 实现方案 Spring Cloud Alibaba 引入 单体架构 当我们刚开始学开发的时候&#xff0c;基本都是单体架构&#xff0c;就是把一个项目的所有业务的实现功能都打包在一个 war 包或者 Jar 包中。…