QtConcurrent和QFuture的使用

        在Qt中,有时候我们会遇到这样一种情况,需要执行一个很长时间的操作,这时候我们的主界面就会卡住。我们的通常做法就是把这个很长时间的操作扔到线程里去处理,可以使用标准库中的线程也可以使用QThread。

        如果我们要在这个很长时间的操作之后,在UI上显示一些东西,或者改变一些UI上的控件的状态。这种时候标准库的线程就不是很好用了,通常这种时候我们会使用QThread,创建一个新的类继承QObject,然后再这个新的类里面写一堆信号和槽,和主线程通讯传递消息改变UI界面。但是这种太麻烦了,每次都要新创建一个类和一堆信号,十分不好管理。

        在查了资料后,我发现了Qt有提供专门并发的类QtConcurrent,以及接收异步计算结果的QFuture类。在这里记录一下QtConcurrent和QFuture的使用。


介绍:

        Concurrent是并发的意思,而QtConcurrent同std一样,是一个命名空间(namespace),想使用它需要先在Project工程文件中导入模块,并包含头文件QtConcurrent/QtConcurrent。

QT += concurrent

#include <QtConcurrent/QtConcurrent>

        QtConcurrent提供了一些高级的 API,使得在编写多线程的时候,无需使用低级线程原语,如读写锁,等待条件或信号。使用QtConcurrent编写的程序会根据可用的处理器内核数自动调整使用的线程数。

        QtConcurrent中使用最多的是它的run()函数,每调用一次QtConcurrent::run()函数,就会新建立一个线程运行我们让它执行的函数。run()函数的返回值QFuture类型的,run()函数是有很多重载,这里就简单讲几个常用的。


QtConcurrent::run示例:

调用全局函数: 

函数原型:
QFuture<T> QtConcurrent::run(Function func, ...)

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QDebug>
#include <QThread>
#include <QFuture>
#include <QtConcurrent/QtConcurrent>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

QString func(QString content)
{
    QString str = QString("%1 %2 %3.").arg(__FUNCTION__).arg(content).arg(quintptr(QThread::currentThreadId()));
    return str;
}

void MainWindow::on_pushButton_clicked()
{
    QFuture<QString> fut1 = QtConcurrent::run(func, QString("Thread_1"));// 用QFuture获取该函数的运行结果,参数2:向func函数传递的参数
    QFuture<QString> fut2 = QtConcurrent::run(func, QString("Thread_2"));
    QString result1 = fut1.result();
    QString result2 = fut2.result();
    qDebug() << result1;
    qDebug() << result2;
    fut1.waitForFinished();// waitForFinished()保证线程执行完毕
    fut2.waitForFinished();
}

        这里使用QFuture的result()函数获取QtConcurrent::run()执行的函数的返回值,然后打印出来,打印结果如下:

调用匿名函数: 

         上面的示例中的func也可以改成匿名函数,只是写法上不同,结果都是一样的:

QFuture <QString> future =  QtConcurrent::run([=](){
    QString str = QString("%1 %2 %3.").arg(__FUNCTION__).arg("Thread_1").arg(quintptr(QThread::currentThreadId()));
    return str;
});
QFuture <QString> future2 = QtConcurrent::run([=](){
    QString str = QString("%1 %2 %3.").arg(__FUNCTION__).arg("Thread_2").arg(quintptr(QThread::currentThreadId()));
    return str;
});

 调用成员函数:

         同样的,QtConcurrent::run()也可以调用成员函数,第一个参数必须是一个const引用或一个指向该类实例的指针,第二个参数是函数指针:

QString MainWindow::func(QString content)
{
    QString str = QString("%1 %2 %3.").arg(__FUNCTION__).arg(content).arg(quintptr(QThread::currentThreadId()));
    return str;
}

QFuture<QString> fut1 = QtConcurrent::run(this, &MainWindow::func, QString("Thread_1"));
QFuture<QString> fut2 = QtConcurrent::run(this, &MainWindow::func, QString("Thread_2"));

调用其他类的成员函数: 

         调用其他类的成员函数,包括Qt提供的函数也是同样的方法:

QByteArray bytearray = "hello,world";
QFuture<QList<QByteArray>> future = QtConcurrent::run(bytearray, &QByteArray::split, ',');

 使用线程池中的线程调用函数:

// 函数原型

template <typename T> QFuture<T> QtConcurrent::run(QThreadPool *pool, Function function, ...)


使用QFutureWatcher监视线程:

        QFuture 表示异步计算的结果,QFutureWatcher 则允许使用信号和槽监视 QFuture,也就是说,QFutureWatcher 是为 QFuture 而生的。

        示例,开始计算并当完成时通过槽获取结果:

// 实例化对象,并连接槽到 finished() 信号,等线程中函数完成后就会触发连接的槽。
MyClass myObject;
QFutureWatcher<int> watcher;
connect(&watcher, &QFutureWatcher<QVector<complex<double>>>::finished, &myObject, &MyClass::handleFinished);
 
// 开始计算
QFuture<int> future = QtConcurrent::run(...);
watcher.setFuture(future);

        匿名函数的写法:

QFutureWatcher<QVector<complex<double>>>* pwatcher = new QFutureWatcher<QVector<complex<double>>>;
QFuture<QVector<complex<double>>> future = QtConcurrent::run([=]() {
    QVector<complex<double>> result;
    // 费时操作在这里执行,之后返回QVector<complex<double>>类型的结果

    return result;
});
connect(pwatcher, &QFutureWatcher<QVector<complex<double>>>::finished, this, [=]() {
    // 使用pwatcher->result()获取在QtConcurrent::run()中的返回值
    QVector<complex<double>> img2result = pwatcher->result();
    // 执行费时操作完成之后的操作,例如改变UI界面的控件
});
pwatcher->setFuture(future);

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java泛型机制

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a;每天一个知识点 ✨特色专栏&#xff1a…

javacv 基础04-读取mp4,avi等视频文件并截图保存图片到本地

javacv 读取mp4,avi等视频文件并截图保存图片到本地 代码如下&#xff1a; package com.example.javacvstudy;import org.bytedeco.javacv.FFmpegFrameGrabber; import org.bytedeco.javacv.Frame; import org.bytedeco.javacv.Java2DFrameConverter;import javax.imageio.Im…

单元测试:优雅编写Kotlin单元测试

一、MockK简介 MockK是一款功能强大、易于使用的Kotlin mocking框架。在编写单元测试时&#xff0c;MockK能够帮助我们简化代码、提高测试覆盖率&#xff0c;并改善测试的可维护性。除了基本用法外&#xff0c;MockK还提供了许多额外的功能和灵活的用法&#xff0c;让我们能够…

ARM DIY(四)WiFi 调试

文章目录 焊接打开内核编译选项重新编译内核烧录 && 运行 && 测试完善脚本测速手搓天线正式天线 焊接 换个粗点的风枪嘴&#xff0c;让热风覆盖 RTL8823BS 整体模块&#xff0c;最终实现自动归位 焊接 SDIO 接口的上拉电阻以及复位引脚上拉电阻 硬件部分就这…

linux centos7 bash中字符串反向输出

给定一个字符串&#xff0c;如何反向(倒序)输出&#xff1f; 字符串反转的方法&#xff1a;a.对各个字符位置进行循环调换&#xff08;从原字符串左边取出放在新字符串的右边&#xff1b;从原字符串右边取出放在新字符串的左边&#xff09;。b.对各个字符由水平排列转为垂直排…

时序预测 | MATLAB实现EEMD-SSA-LSTM、EEMD-LSTM、SSA-LSTM、LSTM时间序列预测对比

时序预测 | MATLAB实现EEMD-SSA-LSTM、EEMD-LSTM、SSA-LSTM、LSTM时间序列预测对比 目录 时序预测 | MATLAB实现EEMD-SSA-LSTM、EEMD-LSTM、SSA-LSTM、LSTM时间序列预测对比预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 时序预测 | MATLAB实现EEMD-SSA-LSTM、E…

渗透测试漏洞原理之---【失效的访问控制】

文章目录 1、失效的访问控制1.1、OWASP Top 101.1.1、A5:2017-Broken Access Control1.1.2、A01:2021 – Broken Access Control 1.2、失效的访问控制类别1.2.1、水平越权1.2.2、垂直越权 1.3、攻防案例1.3.1、Pikachu靶场 Over Permision1.3.2、DVWA越权利用失效的访问控制漏洞…

大数据课程K16——Spark的梯度下降法

文章作者邮箱&#xff1a;yugongshiyesina.cn 地址&#xff1a;广东惠州 ▲ 本章节目的 ⚪ 了解Spark的梯度下降法&#xff1b; ⚪ 了解Spark的梯度下降法家族&#xff08;BGD&#xff0c;SGD&#xff0c;MBGD&#xff09;&#xff1b; ⚪ 掌握Spark的MLlib实现…

Data Rescue Professional for Mac:专业的数据恢复工具

在数字化时代&#xff0c;我们的生活和工作离不开电脑和存储设备。但是&#xff0c;意外情况时常发生&#xff0c;例如误删除文件、格式化硬盘、病毒攻击等&#xff0c;这些都可能导致重要的数据丢失。面对数据丢失&#xff0c;我们迫切需要一款可靠的数据恢复工具。今天&#…

剪枝基础与实战(5): 剪枝代码详解

对模型进行剪枝,我们只对有参数的层进行剪枝,我们基于BatchNorm2d对通道重要度 γ \gamma γ参数进行稀释训练。对BatchNorm2d及它的前后层也需要进行剪枝。主要针对有参数的层:Conv2d、BatchNorm2d、Linear。但是我们不会对Pool2d 层进行剪枝,因为Pool2d只用来做下采样,没…

在windows下进行maven安装配置

下载 https://maven.apache.org/download.cgi 安装配置 配置settings.xml文件 如果需要修改仓库的地址&#xff0c;可新增一条localRepository的记录&#xff0c;加上存放下载jar包的地址。 设置Maven镜像下载地址 配置完成&#xff0c;在命令行输入mvn help:system测试&#…

科创板50ETF期权交易:详细规则、费用、保证金和开户攻略

科创板50ETF期权是指以科创板50ETF为标的资产的期权合约。科创板50ETF是由交易所推出的一种交易型开放式指数基金&#xff08;ETF&#xff09;&#xff0c;旨在跟踪科创板50指数的表现&#xff0c;下文介绍科创板50ETF期权交易&#xff1a;详细规则、费用、保证金和开户攻略&am…

uni-app中使用iconfont彩色图标

uni-app中使用iconfont彩色图标 大家好&#xff0c;今天我们来学习一下uni-app中使用iconfont彩色图标&#xff0c;好好看&#xff0c;好好学&#xff0c;超详细的 第一步 首先&#xff0c;从iconfont官网&#xff08;iconfont-阿里巴巴矢量图标库&#xff09;选择自己需要的图…

QT6为工程添加资源文件,并在ui界面引用

以添加图片资源为例 右键工程名字&#xff08;不是最上面的名字&#xff09;&#xff0c;点击添加现有文件 这种方式虽然添加到了工程中&#xff0c;但不能在UI设计界面完成引用。主要原因可能是未把文件放入到项目资源文件中&#xff0c;以下面一种方式可以看出区别。 点击添…

FFmpeg报错:Connection to tcp://XXX?timeout=XXX failed: Connection timed out

一、现象 通过FFmpeg&#xff08;FFmpeg的版本是5.0.3&#xff09;拉摄像机的rtsp流获取音视频数据&#xff0c;执行命令&#xff1a; ./ffmpeg -timeout 3000000 -i "rtsp://172.16.17.156/stream/video5" 报错&#xff1a;Connection to tcp://XXX?timeoutXXX …

生态项目|Typus如何用Sui特性制作动态NFT为DeFi赋能

对于许多人来说&#xff0c;可能因其涉及的期权、认购和价差在内的DeFi而显得晦涩难懂&#xff0c;但Typus Finance找到了一种通过动态NFT使体验更加丰富的方式。Typus NFT系列的Tails为用户带来一个外观逐渐演变并在平台上提升活动水平时获得新特权的角色。 Typus表示&#x…

解决npm install报错: No module named gyp

今天运行一个以前vue项目&#xff0c;启动时报错如下&#xff1a; ERROR Failed to compile with 1 error上午10:19:33 error in ./src/App.vue?vue&typestyle&index0&langscss& Syntax Error: Error: Missing binding D:\javacode\Springboot-MiMall-RSA\V…

【数据结构】2015统考真题 6

题目描述 【2015统考真题】求下面的带权图的最小&#xff08;代价&#xff09;生成树时&#xff0c;可能是Kruskal算法第2次选中但不是Prim算法&#xff08;从v4开始&#xff09;第2次选中的边是&#xff08;C&#xff09; A. (V1, V3) B. (V1, V4) C. (V2, V3) D. (V3, V4) …

maven本地安装jar包install-file,解决没有pom的问题

背景&#xff1a; 公司因为权限问题&#xff0c;没有所有的代码&#xff0c;内部maven还在搭建&#xff0c;所以需要拿到同事的jar包&#xff0c;本地install&#xff1a; mvn install:install-file -DgroupIdcom..framework -DartifactIdcloud-api -Dversion1.0.0-SNAPSHOT …

【C语言】字符函数,字符串函数,内存函数

大家好&#xff01;今天我们来学习C语言中的字符函数&#xff0c;字符串函数和内存函数。 目录 1. 字符函数 1.1 字符分类函数 1.2 字符转换函数 1.2.1 tolower&#xff08;将大写字母转化为小写字母&#xff09; 1.2.2 toupper&#xff08;将小写字母转化为大写字母&…