[Qt] QFuture和QFutureWatcher

[Qt] QFuture和QFutureWatcher

第一次看到这两个类,感觉很有意思,也很有用。整理如下:

先来说说QFuture:
QFuture类代表了一个异步调用的结果。而这个异步调用需要使用Qt Concurrent架构中的API。
QFuture让线程可以通过某个后期产生的结果来实现同步。这个结果可以是任何拥有默认构造函数和拷贝构造函数的类型。如果这个结果在调用其result(), resultAt(), 或者 results()方法时还没有准备好,QFuture将会一直等到结果准备好。可以通过它的isResultReadyAt()方法来检测结果是否准备好。对于QFuture对象需要准备多个结果的情况,其resultCount()方法会返回连续结果的数量。这意味着从0遍历到resultCount()总是安全的。QFuture提供了Java类型的遍历器QFutureIterator以及STL类型的遍历器QFuture::const_iterator,可以根据自己的编程习惯使用它们来遍历结果。
QFuture提供了很多方法来跟正在进行的异步调用交互。例如可以通过其candel()方法来取消执行。可以通过setPaused(),pause(), resume(), 或者 togglePaused()来停止执行。这里需要注意不是所有的异步执行都可以取消或者停止。例如通过QtConcurrent::run()的future是不能被取消的,而通过QtConcurrent::mappedReduced()获得的future则可以被取消。

可以通过progressValue(), progressMinimum(), progressMaximum(), and progressText()方法来获得执行的进度信息。waitForFinished()方法会导致当前线程阻塞只到异步执行结束。

异步执行的状态信息可以通过isCanceled(), isStarted(), isFinished(), isRunning(), 或者 isPaused()方法来获得。

QFuture是一个轻量级的引用计数类,可以直接使用值传递方式。

QFuture<void>比较特殊,它表示不返回异步调用的结果。任何QFuture<T>对象都可以赋值或者拷贝给QFuture<void>对象。QFuture<void>对于结果数据不需要而只需要状态或者进度信息的情况比较有用。

如果想通过信号槽来跟异步调用实现交互,则要使用下面的QFutureWatcher。
QFutureWatcher是为QFuture而生的。通过QFutureWatcher我们可以通过信号槽来监视一个QFuture。

通过setFuture()方法可以开始监视一个QFuture。

为了方便,QFuture的很多方法我们可以直接通过QFutureWatcher来访问,如progressValue(), progressMinimum(), progressMaximum(), progressText(), isStarted(), isFinished(), isRunning(), isCanceled(), isPaused(), waitForFinished(), result(), and resultAt(). The cancel(), setPaused(), pause(), resume(), and togglePaused(),这些方法都是以槽的形式出现的。

下面我们来看一下SDK中给出的例子:
  1. //构造QFutureWatcher以及连接信号槽
  2. MyClass myObject;
  3. QFutureWatcher<int> watcher;
  4. connect(&watcher, SIGNAL(finished()), &myObject, SLOT(handleFinished()));

  5. //开始异步调用
  6. QFuture<int> future = QtConcurrent::run(...);
  7. watcher.setFuture(future);
复制代码
上面这个例子本身没有问题。但我们经常会在类中使用QFutureWatcher,这时就要注意了,很多人在栈上构造QFutureWatcher,结果出问题了,qtcentre上就这么一个例子大家可以自己去看看:
http://www.qtcentre.org/threads/ ... -signal-not-working

原因很简单我就不说了




==================================
#include <QtCore>
 
// helloconcurrent/main.cpp
void hello()
{
    qDebug() << "Hello from thread " << QThread::currentThread();
}
 
int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);
    ///重点分析下QFuture 和QtConcurrent这两个 关键字的用法!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    QFuture<void> future = QtConcurrent::run(hello);//thread-self自己函数就是一个线程.  暂时不懂QFuture和QtConcurrent的具体用法。
    qDebug() << "hello from GUI thread " << QThread::currentThread();
    future.waitForFinished();
    return 0;
}
 
 
<think>我们之前讨论了QtConcurrent的使用情况,现在用户想了解QFuture的使用方法场景。根据用户提供的引用内容,尤其是引用[1]引用[3]中提到了QFuture的使用,我们可以重点围绕这些内容展开。用户引用[1]展示了一个使用QFutureQFutureWatcher的示例:读取图像文件并在完成后设置图像。引用[3]则提到QFuture用于异步执行耗时操作并获取结果。我们需要整理出QFuture的核心使用方法典型场景,同时结合最佳实践注意事项。结构计划:1.QFuture的作用基本概念2.创建QFuture的几种方式(重点QtConcurrent::run)3.获取结果的两种模式(阻塞与非阻塞)4.使用QFutureWatcher监控任务状态5.典型应用场景举例6.线程安全注意事项7.相关API比较(如与std::future)8.生成相关问题注意:根据系统指令,数学公式要用$...$,代码块要规范,同时引用标记要自然添加。</think> ### QFutureQt 中的使用方法与场景 QFutureQt 提供的异步编程核心类,用于管理并行任务的执行结果获取,通常与 `QtConcurrent` 或 `QThreadPool` 配合使用。 --- #### 一、核心使用方法 1. **创建异步任务** 使用 `QtConcurrent::run` 启动任务,返回 `QFuture<T>`: ```cpp // 定义任务函数(读取大文件) QImage loadImage(const QString &filePath) { QImage img; img.load(filePath); // 耗时操作 return img; } // 启动异步任务[^1] QFuture<QImage> future = QtConcurrent::run(loadImage, "/images/large.jpg"); ``` 2. **结果获取方式** - **阻塞等待**(主线程暂停) ```cpp QImage result = future.result(); // 阻塞直到任务完成 ``` - **非阻塞监听**(推荐) 通过 `QFutureWatcher` 异步监听: ```cpp QFutureWatcher<QImage> *watcher = new QFutureWatcher(this); connect(watcher, &QFutureWatcher::finished, [=]() { QImage img = future.result(); showImage(img); // 在 GUI 线程安全更新界面[^1] }); watcher->setFuture(future); // 绑定监听器 ``` 3. **任务控制** ```cpp future.cancel(); // 请求取消任务 future.pause(); // 暂停任务(需任务内检测) future.resume(); // 恢复暂停任务 future.isFinished();// 检测任务状态 ``` --- #### 二、典型应用场景 1. **I/O 密集型操作** - 文件加载/保存 - 网络数据下载 ```cpp // 并行下载多个文件 QList<QFuture<QByteArray>> downloads; for (auto &url : urls) { downloads << QtConcurrent::run(downloadFile, url); } ``` 2. **数据处理并行化** - 图像/视频处理 - 大数据集过滤/转换 ```cpp // 并行处理图像组 QList<QImage> images = {...}; auto processImage = [](QImage img) { return img.mirrored(); // 镜像处理 }; QList<QFuture<QImage>> futures = QtConcurrent::map(images, processImage); ``` 3. **耗时计算任务** - 数学计算(如矩阵运算) - 算法执行(如路径规划) ```cpp QFuture<double> calcFuture = QtConcurrent::run([] { return integrate(sin, 0, M_PI, 1e-6); // 数值积分 }); ``` 4. **延迟初始化** ```cpp // 异步初始化资源 QFuture<void> initTask = QtConcurrent::run(initDatabase); ``` --- #### 三、关键技术细节 1. **线程安全性** - QFuture 自身线程安全 - **共享数据需加锁**: ```cpp QMutex mutex; QtConcurrent::run([&] { QMutexLocker lock(&mutex); sharedData.update(); }); ``` 2. **与 GUI 交互** - 禁止在子线程直接操作 GUI - 通过信号槽传递结果: ```cpp emit imageReady(future.result()); // 信号触发主线程更新 ``` 3. **资源管理** - 使用 `QFutureWatcher` 自动释放资源 ```cpp watcher->deleteLater(); // 对象自动析构 ``` 4. **任务拆分优化** - 大任务分割为子任务提交到线程池: $$T_{\text{总}} = \max_{1 \leq i \leq n}(T_i) + \epsilon$$ 其中 $n$ 为子任务数,$T_i$ 为子任务耗时 --- #### 四、对比其他方案 | 方案 | 适用场景 | 优势 | |---------------------|-----------------------------------|--------------------------| | `QFuture` + `QtConcurrent` | 无状态并行任务 | 自动线程管理 | | `QThread` | 需持续运行的任务(如 TCP 服务) | 精细控制生命周期 | | `std::async` | 跨平台非 GUI 程序 | 标准 C++ 兼容性 | > 数据源:[^2][^3] ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值