当前位置: 首页 > backend >正文

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.xdnf.cn/news/4236.html

相关文章:

  • Linux 更改内存交换 swap 为 zram 压缩,减小磁盘写入
  • Android学习总结之Java和kotlin区别
  • Listremove数据时报错:Caused by: java.lang.UnsupportedOperationException
  • 深度解读 ARM 全新白皮书——《重塑硅基:AI 时代的新基石》
  • RabbitMQ-api开发
  • 美团Java高级配送员面经分享|玩梗版
  • Python实例题:高德API+Python解决租房问题
  • Spring Web MVC————入门(1)
  • 15.Spring Security对Actuator进行访问控制
  • 2025年北京市职工职业技能大赛第六届信息通信行业网络安全技能大赛初赛-wp
  • OpenGl实战笔记(2)基于qt5.15.2+mingw64+opengl实现纹理贴图
  • Mysql order by 用法
  • 国标GB28181视频平台EasyCVR安防系统部署知识:如何解决异地监控集中管理和组网问题
  • Latex排版问题:图片单独占据一页
  • 极狐GitLab 如何将项目共享给群组?
  • k倍区间--线段树60/map+思维100
  • ​​6 .数据库规范化与关系理论复习大纲​
  • 64.微服务保姆教程 (七) RocketMQ--分布式消息中间件
  • 常见汇编代码及其指定
  • MySQL 8.0 深度优化:从索引革命到事务增强
  • C语言结构体内存对齐使用场景
  • 飞牛云如何开启及使用ssh:小白用户上手指南-家庭云计算专家
  • Laravel 12 基于 EMQX 实现 MQTT 消息发送与接收
  • 电商数据接口开发进阶:京东 API 实时商品信息采集技术解析​
  • 通过 ModernBERT 实现零样本分类的性能提升
  • Nginx 安全防护与HTTPS部署
  • Super VLAN配置
  • Ubuntu 系统中解决 Firefox 中文显示乱码的完整指南
  • 荣耀A8互动娱乐组件部署实录(第3部分:控制端结构与房间通信协议)
  • 机器学习例题——预测facebook签到位置(K近邻算法)和葡萄酒质量预测(线性回归)