【QT进阶】Qt线程与并发之QtConcurrent返回值与run方法的参数说明

本文主要是介绍【QT进阶】Qt线程与并发之QtConcurrent返回值与run方法的参数说明,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

往期回顾

【QT进阶】Qt线程与并发之线程和并发的简单介绍-CSDN博客

【QT进阶】Qt线程与并发之创建线程的三种方法(超详细介绍)-CSDN博客

【QT进阶】Qt线程与并发之QtConcurrent的简单介绍-CSDN博客

 【QT进阶】Qt线程与并发之QtConcurrent返回值与run方法的参数说明

一、QtConcurrent::run的参数说明

QtConcurrent::run函数的参数类型是模板化的,它可以接受任意可调用对象(函数指针、成员函数指针、函数对象、Lambda表达式等)作为参数。这意味着我们可以传递任何可调用对象作为要在后台线程中执行的任务。

1、QtConcurrent::run函数的签名

template <typename T>
QFuture<T> QtConcurrent::run(T (*functionPointer)(), ...);

这里的T是任务函数的返回类型。我们可以传递一个普通的函数指针,然后在后台线程中执行该函数。除了普通的函数指针外,我们还可以传递其他可调用对象,只要它们符合函数签名的要求即可。

我们看几个参数示例

 2、参数示例

QtConcurrent::run函数的参数,可以是全局函数,也可以是类成员函数,还可以是lambda表达式,同时还可以是不带参数的。

1、类成员函数做run参数

intnum1=0;
int num2 = 0;
QFuture<int> future = QtConcrrent::run(this, &MainWindow::timeTask, num1, num2);

2、用全局函数做参数 

static int timeTask()
int i= 0;
while(i < 123456789)
{
QFuture<int> future = QtConcurrent::run(timeTask);
i++;
}
return i;

3、lambda表达式做参数 

// 在后台线程中执行Lambda表达式
QFuture<int> future = QtConcurrent::run([](){// 执行一些操作return result;
});

对比一下,首先run方法里是可以带参数的,其次,如果是用类成员函数做参数,是需要添加this并以类名引导,但是如果是用全局函数做参数,则都不用加,直接放函数名就可以了。

二、获取QtConcurrent的返回值 

1、获取方式

获取QtConcurrent的结果,需要使用QFutureWatcher类,链接它的信号finished,然后给watcher设置future,当监控到future执行结束后,可以获取它的执行结果,调用的是result()函数:

qDebug() << "return = " << watcher->result();

2、执行过程

 2.1、创建QFutureWatcher对象

创建一个 QFutureWatcher 对象,用于监视 QFuture 对象的执行状态。

    QFutureWatcher<int>* fw = new QFutureWatcher<int>;
2.2、执行 成员函数 timeTask

在一个新线程中执行 ch74 类的成员函数 timeTask,并传递 num01 和 num02 作为参数。 

    QFuture<int> ft = QtConcurrent::run(this, &ch74::timeTask, num01, num02);
2.3、关联QFuture<int> 对象

将 QFuture<int> 对象与 QFutureWatcher 相关联,以便监视其执行状态。 

fw->setFuture(ft);
2.4、连接 finished信号

连接 QFutureWatcher 的 finished信号,由于给watcher设置future,当监控到future执行结束后,可以获取它的执行结果,调用的是result()函数: 

    connect(fw, &QFutureWatcher<int>::finished, [&]{qDebug() << "QFutureWatcher finished";qDebug() << "result = " << fw->result();//qDebug() << "num1 = " << num1;//qDebug() << "num2 = " << num2;});
2.5、循环处理事件

通过循环处理事件来保持界面的响应性,直到 QFuture 执行完成。

    //没完成的时候循环处理事件来保持界面的响应性while (!ft.isFinished()){QApplication::processEvents(QEventLoop::AllEvents, 30);}

QApplication::processEvents

函数用于处理事件循环中的事件,确保界面的响应性。调用该函数会处理当前事件队列中的所有事件,直到事件队列为空或者达到指定的最大处理时间。 

QEventLoop::AllEvents

参数表示处理所有类型的事件,包括用户输入事件、定时器事件、绘图事件等。

30 参数表示最大处理时间为30毫秒,即函数最多处理30毫秒的事件后返回。这样可以避免在处理事件的过程中阻塞主线程过长时间,确保界面的及时响应。

3、最终代码

#include "ch74.h"
#include <QDebug>
#include <QtConcurrent>
#include <QFuture>
#include <QFutureWatcher>ch74::ch74(QWidget *parent): QWidget(parent)
{ui.setupUi(this);
}ch74::~ch74()
{}int ch74::timeTask(int& num1, int& num2)
{for (int i = 0; i < 1000; i++){num1++;num2++;qDebug() << num1;qDebug() << num2;}return num1 + num2;
}void ch74::on_pushButton_clicked()
{int num01 = 0;int num02 = 0;//创建 QFutureWatcher 对象,用于监视一个 QFuture 对象的执行状态QFutureWatcher<int>* fw = new QFutureWatcher<int>;//通过 QtConcurrent::run 函数在一个新线程中执行 ch74 类的成员函数 timeTask.(并发)// num01 和 num02 作为参数传递给 timeTask 函数。QFuture<int> ft = QtConcurrent::run(this, &ch74::timeTask, num01, num02);//通过 fw->setFuture(ft) 将 QFuture<int> 对象与 QFutureWatcher 相关联,//这样 QFutureWatcher 就能监视 QFuture 对象的执行状态fw->setFuture(ft);//连接 QFutureWatcher 的 finished 信号,当 QFuture 执行完成时输出调试信息,注意这里由于捕获的是指针fw
//所以lambda表达式里用的是[&]而不是[=]connect(fw, &QFutureWatcher<int>::finished, [&] {qDebug() << "QFutureWatcher finished";qDebug() << "result = " << fw->result();//qDebug() << "num1 = " << num1;//qDebug() << "num2 = " << num2;});//没完成的时候循环处理事件来保持界面的响应性while (!ft.isFinished()){//QApplication::processEvents 函数用于处理事件循环中的事件,确保界面的响应性//调用该函数会处理当前事件队列中的所有事件,直到事件队列为空或者达到指定的最大处理时间QApplication::processEvents(QEventLoop::AllEvents, 30);}
}

以上就是QtConcurrent返回值与run方法的参数说明的简单介绍

都看到这里了,点个赞再走呗朋友~

加油吧,预祝大家变得更强!

这篇关于【QT进阶】Qt线程与并发之QtConcurrent返回值与run方法的参数说明的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/937352

相关文章

Before和BeforeClass的区别及说明

《Before和BeforeClass的区别及说明》:本文主要介绍Before和BeforeClass的区别及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Before和BeforeClass的区别一个简单的例子当运行这个测试类时总结Before和Befor

Python pip下载包及所有依赖到指定文件夹的步骤说明

《Pythonpip下载包及所有依赖到指定文件夹的步骤说明》为了方便开发和部署,我们常常需要将Python项目所依赖的第三方包导出到本地文件夹中,:本文主要介绍Pythonpip下载包及所有依... 目录步骤说明命令格式示例参数说明离线安装方法注意事项总结要使用pip下载包及其所有依赖到指定文件夹,请按照以

Maven 配置中的 <mirror>绕过 HTTP 阻断机制的方法

《Maven配置中的<mirror>绕过HTTP阻断机制的方法》:本文主要介绍Maven配置中的<mirror>绕过HTTP阻断机制的方法,本文给大家分享问题原因及解决方案,感兴趣的朋友一... 目录一、问题场景:升级 Maven 后构建失败二、解决方案:通过 <mirror> 配置覆盖默认行为1. 配置示

SpringBoot排查和解决JSON解析错误(400 Bad Request)的方法

《SpringBoot排查和解决JSON解析错误(400BadRequest)的方法》在开发SpringBootRESTfulAPI时,客户端与服务端的数据交互通常使用JSON格式,然而,JSON... 目录问题背景1. 问题描述2. 错误分析解决方案1. 手动重新输入jsON2. 使用工具清理JSON3.

使用jenv工具管理多个JDK版本的方法步骤

《使用jenv工具管理多个JDK版本的方法步骤》jenv是一个开源的Java环境管理工具,旨在帮助开发者在同一台机器上轻松管理和切换多个Java版本,:本文主要介绍使用jenv工具管理多个JD... 目录一、jenv到底是干啥的?二、jenv的核心功能(一)管理多个Java版本(二)支持插件扩展(三)环境隔

Java中Map.Entry()含义及方法使用代码

《Java中Map.Entry()含义及方法使用代码》:本文主要介绍Java中Map.Entry()含义及方法使用的相关资料,Map.Entry是Java中Map的静态内部接口,用于表示键值对,其... 目录前言 Map.Entry作用核心方法常见使用场景1. 遍历 Map 的所有键值对2. 直接修改 Ma

从基础到进阶详解Pandas时间数据处理指南

《从基础到进阶详解Pandas时间数据处理指南》Pandas构建了完整的时间数据处理生态,核心由四个基础类构成,Timestamp,DatetimeIndex,Period和Timedelta,下面我... 目录1. 时间数据类型与基础操作1.1 核心时间对象体系1.2 时间数据生成技巧2. 时间索引与数据

Mybatis Plus Join使用方法示例详解

《MybatisPlusJoin使用方法示例详解》:本文主要介绍MybatisPlusJoin使用方法示例详解,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,... 目录1、pom文件2、yaml配置文件3、分页插件4、示例代码:5、测试代码6、和PageHelper结合6

Java中实现线程的创建和启动的方法

《Java中实现线程的创建和启动的方法》在Java中,实现线程的创建和启动是两个不同但紧密相关的概念,理解为什么要启动线程(调用start()方法)而非直接调用run()方法,是掌握多线程编程的关键,... 目录1. 线程的生命周期2. start() vs run() 的本质区别3. 为什么必须通过 st

C#之List集合去重复对象的实现方法

《C#之List集合去重复对象的实现方法》:本文主要介绍C#之List集合去重复对象的实现方法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录C# List集合去重复对象方法1、测试数据2、测试数据3、知识点补充总结C# List集合去重复对象方法1、测试数据