Qt使用QtConcurrent::run实现异步等待和同步调用

 更新时间:2025年09月18日 10:48:49   作者:__ocean  
Qt使用QtConcurrent::run实现C#中类似async await的用法,虽不如C#的async/await灵活,但可满足业务需求并提升代码可读性,下面就来详细的介绍一下QtConcurrent::run实现异步等待和同步调用

在使用Qt进行开发时,经常需要使用异步方法,不同于C#的async/await,Qt中提供了QtConcurrent::run接口方法可供调用,习惯了C#的await,便想着能不能封装几个类似的函数在项目中使用,探索了下,有如下几个方案

首先定义全局线程池

	inline QThreadPool* globalThreadPool() 
	{
		static QThreadPool* pool = []() {
			QThreadPool* p = new QThreadPool;
			p->setMaxThreadCount(QThread::idealThreadCount());
			return p;
			}();
		return pool;
	}

方案一,最简单的封装调用,直接异步调用,无任何返回结果,也不会卡住调用线程:

	auto CallAsync = [](auto func){
		QtConcurrent::run(globalThreadPool(), func);
	};

调用时用法如下:

CallAsync([](){
	// do something in theadpool...
});

方案二,如果我们想在异步执行时,调用线程同步等待,可封装如下:

auto AwaitCallAsync = [](auto func, int timeoutSeconds = 5) -> bool
{        
    QFuture<void> future = QtConcurrent::run(globalThreadPool(), func);
    
    // 使用智能指针管理对象生命周期
    auto watcher = std::make_shared<QFutureWatcher<void>>();
    auto loop = std::make_shared<QEventLoop>();
    auto timer = std::make_shared<QTimer>();
    
    bool timedOut = false;    
    if (timeoutSeconds > 0) {
        timer->setInterval(timeoutSeconds * 1000);
        timer->setSingleShot(true);
        QObject::connect(timer.get(), &QTimer::timeout, [&timedOut, loop]() {
            timedOut = true;
            loop->quit();
        });
        timer->start();
    }    
    QObject::connect(watcher.get(), &QFutureWatcher<void>::finished, loop.get(), &QEventLoop::quit);
    watcher->setFuture(future);    
    loop->exec();
    
    // 清理资源
    if (!timedOut && timeoutSeconds > 0) {
        timer->stop();
    }    
    return !timedOut; // 返回是否正常完成
};

此时,执行AwaitCallAsync时,调用线程会同步等待但并不会卡住线程,为了避免长时间等待,也可以添加超时参数。

方案三,有时,我们在希望在异步函数调用完成后能回到调用线程继续执行,那么可以添加QFutureWatcher,监控异步函数的执行,然后在QFutureWatcher发送finished时执行另一个函数,如下:

auto CallAsyncWithCallback = [](auto func_async, auto func_callback){
		auto future = QtConcurrent::run(globalThreadPool(), func_async);
		auto watcher = new QFutureWatcher<void>();
		// 连接信号,此处connect会被自动执行为Qt::QueuedConnection
		QObject::connect(watcher, &QFutureWatcher<void>::finished, [func_callback, watcher]() mutable { 
				func_callback();
				watcher->deleteLater(); // 完成后自动清理
			});
		watcher->setFuture(future);
	}

上面的connect是在调用线程中执行的,而finished信号是在线程池中子线程中发出来的,跨线程所以Qt会选择用Qt::QueuedConnection的方式执行Lambda 表达式。

方案四,有时,我们希望回调函数在特定线程比如主线程中执行,如下:

auto CallAsyncWithUICallback = [](FuncAsync func_async, FuncCallback func_callback_onUI) {
		QtConcurrent::run([func_async, func_callback]() {			
			func_async(); // 在子线程执行异步函数
			
			// 回到主线程执行回调
			QMetaObject::invokeMethod(qApp, [func_callback]() {
				func_callback();
				}, Qt::QueuedConnection);
			});
	}

注意,在调用invokeMethod时,要显示指定Qt::QueuedConnection。

总体来说,C#的async await很灵活很强大,Qt虽然不能与之相比,但经过简单的封装,也能写出比较灵活或者符合自己业务需求而又简洁好读的异步代码。

到此这篇关于Qt使用QtConcurrent::run实现异步等待和同步调用的文章就介绍到这了,更多相关Qt QtConcurrent::run异步等待和同步调用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:

相关文章

  • sigsetjmp的用法总结

    sigsetjmp的用法总结

    sigsetjmp()会保存目前堆栈环境,然后将目前的地址作一个记号,而在程序其他地方调用siglongjmp()时便会直接跳到这个记号位置,然后还原堆栈,继续程序的执行
    2013-09-09
  • 深入C++中API的问题详解

    深入C++中API的问题详解

    本篇文章是对C++中API的问题进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • C++中静态存储区与栈以及堆的区别详解

    C++中静态存储区与栈以及堆的区别详解

    本篇文章是对C++中静态存储区与栈以及堆的区别进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • C++ 匈牙利算法案例分析详解

    C++ 匈牙利算法案例分析详解

    这篇文章主要介绍了C++ 匈牙利算法案例分析详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-08-08
  • Matlab中图像数字水印算法的原理与实现详解

    Matlab中图像数字水印算法的原理与实现详解

    数字水印技术作为信息隐藏技术的一个重要分支,是将信息(水印)隐藏于数字图像、视频、音频及文本文档等数字媒体中,从而实现隐秘传输、存储、标注、身份识别、版权保护和防篡改等目的。本文就来讲讲图像数字水印算法的原理与实现,感兴趣的可以了解一下
    2023-04-04
  • 解析如何利用switch语句进行字符统计

    解析如何利用switch语句进行字符统计

    本篇文章是对如何利用switch语句进行字符统计的方法进行了详细的分析介绍,需要的朋友参考下
    2013-06-06
  • C语言实现点菜系统

    C语言实现点菜系统

    这篇文章主要为大家详细介绍了C语言实现点菜系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-06-06
  • C语言简明讲解变量的属性

    C语言简明讲解变量的属性

    我们知道以在 C 语言中的变量有自己的属性,只要在定义变量的时候加上“属性”关键字即可。“属性”关键字指明变量的特有意义,但是 register 关键字只是请求寄存器变量,所以不一定会成功
    2022-04-04
  • QT中对Mat类的一些操作详解

    QT中对Mat类的一些操作详解

    本文主要介绍了QT中对Mat类的一些操作详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-06-06
  • C语言编写基于TCP和UDP协议的Socket通信程序示例

    C语言编写基于TCP和UDP协议的Socket通信程序示例

    这篇文章主要介绍了C语言编写基于TCP和UDP协议的Socket通信程序示例,其中TCP的客户端与服务器端采用多线程实现,需要的朋友可以参考下
    2016-03-03

最新评论