使用QFuture和QFutureWatcher实现不阻塞界面的Async函数
简述
很多时候,在Qt里面需要运行一个耗时函数的时候,为了避免阻塞界面,需要放入非主线程去执行。
实现这样处理的方法有好几种,例如:
- 写一个继承自QThread类,实现run接口;
- 写一个继承自QObject的类,添加槽函数执行任务,创建对象,移入一个QThread中进行调用;
- 写一个QRunnable的子类,创建对象,添加到QThreadPool里面去调用;
上面的方法都比较麻烦些,可以使用QtConcurrent来进行简化。
这里采用基于QtConcurrent的实现,来简化这种异步调用过程,使用QEventLoop来等待执行结束,模拟同步调用。
代码
#include <QDebug>
#include <QEventLoop>
#include <QFutureWatcher>
#include <QtConcurrent/QtConcurrentRun>
#include <functional>
#include <iostream>
template<typename Func, typename... Args>
auto WaitRunAsync(Func&& func, Args&&... args) -> decltype(func(args...))
{
using ReturnType = decltype(func(args...));
// 将函数和参数绑定为一个可调用对象
auto task = std::bind(std::forward<Func>(func), std::forward<Args>(args)...);
// 使用 QtConcurrent::run 异步执行任务
QFuture<ReturnType> future = QtConcurrent::run(task);
// 创建 QFutureWatcher 来监视任务状态
QFutureWatcher<ReturnType> watcher;
if (qApp != nullptr) {
QEventLoop loop;
// 连接信号槽
QObject::connect(&watcher, &QFutureWatcher<ReturnType>::finished, &loop, &QEventLoop::quit);
// 设置 QFutureWatcher 的 future
watcher.setFuture(future);
// 使用 QEventLoop 等待任务完成
loop.exec();
}
else {
// 设置 QFutureWatcher 的 future
watcher.setFuture(future);
// 等待计算完成
watcher.waitForFinished();
}
std::cout << "event loop quit!" << std::endl;
// 返回任务结果
return future.result();
}
// 示例任务函数
int exampleTask(int a, int b)
{
std::cout << "Task is running with arguments: " << a << ", " << b << std::endl;
QThread::sleep(2); // 模拟耗时操作
std::cout << "Task completed!" << std::endl;
return a + b;
}
int main()
{
std::cout << "Main thread ID: " << QThread::currentThreadId() << std::endl;
for (int i = 0; i < 3; ++i) {
std::cout << "run task " << i << std::endl;
// 异步执行任务并等待完成,获取返回值
int result = WaitRunAsync(exampleTask, 10, 20);
std::cout << "Task result: " << result << std::endl;
}
std::cout << "Back to main thread!" << std::endl;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)