QFuture Class
template <typename T> class QFutureQFuture 类表示异步计算的结果。更多
头文件: | #include <QFuture> |
CMake.QFuture | find_package(Qt6 REQUIRED COMPONENTS Core) target_link_libraries(mytarget PRIVATE Qt6::Core) |
qmake: | QT += core |
- 所有成员(包括继承成员)的列表
- 已废弃成员
- QFuture 属于线程类。
注意:该类中的所有函数都是线程安全的,但以下情况除外:
公共类型
class | const_iterator |
ConstIterator |
公共函数
QFuture() | |
QFuture(const QFuture<T> &other) | |
~QFuture() | |
QFuture<T>::const_iterator | begin() const |
void | cancel() |
QFuture<T>::const_iterator | constBegin() const |
QFuture<T>::const_iterator | constEnd() const |
QFuture<T>::const_iterator | end() const |
bool | isCanceled() const |
bool | isFinished() const |
bool | isResultReadyAt(int index) const |
bool | isRunning() const |
bool | isStarted() const |
(since 6.0) bool | isSuspended() const |
(since 6.0) bool | isSuspending() const |
(since 6.0) bool | isValid() const |
(since 6.0) QFuture<T> | onCanceled(Function &&handler) |
(since 6.1) QFuture<T> | onCanceled(QObject *context, Function &&handler) |
(since 6.0) QFuture<T> | onFailed(Function &&handler) |
(since 6.1) QFuture<T> | onFailed(QObject *context, Function &&handler) |
int | progressMaximum() const |
int | progressMinimum() const |
QString | progressText() const |
int | progressValue() const |
T | result() const |
T | resultAt(int index) const |
int | resultCount() const |
QList<T> | results() const |
void | resume() |
(since 6.0) void | setSuspended(bool suspend) |
(since 6.0) void | suspend() |
(since 6.0) T | takeResult() |
(since 6.0) QFuture<QFuture<T>::ResultType<Function>> | then(Function &&function) |
(since 6.1) QFuture<QFuture<T>::ResultType<Function>> | then(QObject *context, Function &&function) |
(since 6.0) QFuture<QFuture<T>::ResultType<Function>> | then(QThreadPool *pool, Function &&function) |
(since 6.0) QFuture<QFuture<T>::ResultType<Function>> | then(QtFuture::Launch policy, Function &&function) |
(since 6.0) void | toggleSuspended() |
(since 6.4) QFuture<U> | unwrap() |
void | waitForFinished() |
QFuture<T> & | operator=(const QFuture<T> &other) |
详细说明
QFuture 允许线程与一个或多个结果同步,这些结果将在稍后时间点准备就绪。结果可以是任何具有默认构造函数、复制构造函数和可能的移动构造函数的类型。如果在调用result(),resultAt(),results() 和takeResult() 函数时结果不可用,QFuture 将等待直到结果可用。您可以使用isResultReadyAt() 函数来确定结果是否就绪。对于报告不止一个结果的 QFuture 对象,resultCount() 函数会返回连续结果的数量。这意味着从 0 到resultCount() 的结果遍历始终是安全的。takeResult()会使一个 future 失效,随后任何访问 result 或 future 中结果的尝试都会导致未定义的行为。isValid() 会告诉您是否可以访问结果。
QFuture 提供了Java 风格的迭代器(QFutureIterator )和STL 风格的迭代器(QFuture::const_iterator )。使用这些迭代器是访问未来结果的另一种方法。
如果需要将一个异步计算的结果传递给另一个异步计算,QFuture 提供了一种使用then() 链接多个顺序计算的便捷方法。onCanceled() 可用于添加一个处理程序,以便在 QFuture 被取消时调用。此外,onFailed() 可用于处理链中出现的任何故障。请注意,QFuture 依赖异常来处理错误。如果不能选择使用异常,也可以通过将错误类型作为 QFuture 类型的一部分来指示 QFuture 的错误状态。例如,你可以使用 std::variant、std::any 或类似类型来保存结果或失败,或者创建你的自定义类型。
下面的示例演示了如何在不使用异常的情况下进行错误处理。假设我们要发送一个网络请求,从网络位置获取一个大文件。然后,我们要将其写入文件系统,并在成功时返回其位置。这两项操作都可能以不同的错误失败。因此,我们使用std::variant
来保存结果或错误:
using NetworkReply = std::variant<QByteArray, QNetworkReply::NetworkError>; enum class IOError { FailedToRead, FailedToWrite }; using IOResult = std::variant<QString, IOError>;
我们使用then() 将这两个操作结合起来:
QFuture<IOResult> future = QtConcurrent::run([url] { ... return NetworkReply(QNetworkReply::TimeoutError); }).then([](NetworkReply reply) { if (auto error = std::get_if<QNetworkReply::NetworkError>(&reply)) return IOResult(IOError::FailedToRead); auto data = std::get_if<QByteArray>(&reply); // try to write *data and return IOError::FailedToWrite on failure ... }); auto result = future.result(); if (auto filePath = std::get_if<QString>(&result)) { // do something with *filePath else // process the error
我们可以按照任意顺序将多个连续操作和处理程序串联起来。例如
QFuture<int> testFuture = ...; auto resultFuture = testFuture.then([](int res) { // Block 1 }).onCanceled([] { // Block 2 }).onFailed([] { // Block 3 }).then([] { // Block 4 }).onFailed([] { // Block 5 }).onCanceled([] { // Block 6 });
根据testFuture
的状态(取消、有异常或有结果),下一个onCanceled() 、onFailed() 或then() 将被调用。因此,如果testFuture
成功执行,Block 1
将被调用。如果也成功了,则会调用下一个then() (Block 4
)。如果testFuture
被取消或异常失败,则将分别调用Block 2
或Block 3
。之后,下一个then() 将被调用,整个过程重复进行。
注意: 如果Block 2
被调用并抛出异常,下面的onFailed() (Block 3
) 将处理该异常。如果onFailed() 和onCanceled() 的顺序颠倒,异常状态将传播到下一个连续程序,并最终在Block 5
中捕获。
在下一个示例中,第一个onCanceled() (Block 2
) 被删除:
QFuture<int> testFuture = ...; auto resultFuture = testFuture.then([](int res) { // Block 1 }).onFailed([] { // Block 3 }).then([] { // Block 4 }).onFailed([] { // Block 5 }).onCanceled([] { // Block 6 });
如果testFuture
被取消,其状态会传播到下一个then() 中,后者也会被取消。因此,在这种情况下,Block 6
将被调用。
未来只能有一个延续。请看下面的示例:
QPromise<int> p; QFuture<int> f1 = p.future(); f1.then([](int) { qDebug("first"); }); QFuture<int> f2 = p.future(); f2.then([](int) { qDebug("second"); }); p.start(); p.addResult(42); p.finish();
在这种情况下,f1
和f2
实际上是同一个 QFuture 对象,因为它们共享相同的内部状态。因此,在f2
上调用then 会覆盖为f1
指定的继续。因此,在执行这段代码时,只会打印"second"
。
QFuture 还提供了与正在运行的计算进行交互的方法。例如,可以使用cancel() 函数取消计算。要暂停或恢复计算,请使用setSuspended() 函数或suspend(),resume() 或toggleSuspended() 方便函数之一。请注意,并非所有正在运行的异步计算都可以取消或暂停。例如,QtConcurrent::run() 返回的 future 不能取消;但 QtConcurrent::mappedReduced() 返回的 future 可以。
进度信息由progressValue(),progressMinimum(),progressMaximum() 和progressText() 函数提供。waitForFinished() 函数会导致调用线程阻塞,等待计算结束,确保所有结果都可用。
可以使用isCanceled(),isStarted(),isFinished(),isRunning(),isSuspending() 或isSuspended() 函数查询 QFuture 所代表的计算状态。
QFuture<void> 专用于不包含任何结果获取函数。任何 QFuture<T> 也可以分配或复制到 QFuture<void> 中。如果只需要状态或进度信息,而不需要实际结果数据,这就非常有用。
要使用信号和槽与运行中的任务交互,请使用QFutureWatcher 。
您还可以使用QtFuture::connect() 将信号连接到 QFuture 对象,该对象将在信号发出时解析。这样就可以像处理 QFuture 对象一样处理信号。例如,如果将它与then() 结合使用,就可以为一个信号附加多个连续程序,这些连续程序在同一线程或新线程中调用。
QtFuture::whenAll() 和QtFuture::whenAny() 函数可用于组合多个期货,并跟踪最后一个或第一个期货何时完成。
可以使用便捷函数QtFuture::makeReadyVoidFuture(),QtFuture::makeReadyValueFuture(),QtFuture::makeReadyRangeFuture() 和QtFuture::makeExceptionalFuture() 创建一个带有值的就绪 QFuture 对象或一个持有异常的 QFuture 对象。
注: 某些 API(见QFuture::then() 或各种QtConcurrent 方法重载)允许将计算调度到特定的线程池。不过,QFuture 实现了一种工作窃取算法,以防止死锁并优化线程使用。因此,计算可直接在请求 QFuture 结果的线程中执行。
注: 要在 QFuture 中启动计算并存储结果,请使用QPromise 或该框架中的某个应用程序接口。 Qt Concurrent框架中的 API。
另请参阅 QPromise,QtFuture::connect(),QtFuture::makeReadyVoidFuture(),QtFuture::makeReadyValueFuture(),QtFuture::makeReadyRangeFuture(),QtFuture::makeExceptionalFuture(),QFutureWatcher, 以及 Qt Concurrent.
成员函数文档
QFuture::QFuture()
构造一个空的、已取消的未来。
QFuture::QFuture(const QFuture<T> &other)
构造other 的副本。
另请参见 operator=().
QFuture::~QFuture()
销毁未来。
请注意,这既不会等待也不会取消异步计算。如果需要确保在销毁 future 之前完成计算,请使用waitForFinished() 或QFutureSynchronizer 。
template <typename U = T, typename = QtPrivate::EnableForNonVoid<U>> QFuture<T>::const_iterator QFuture::begin() const
返回指向未来第一个结果的 ConstSTL 样式迭代器。
另请参阅 constBegin() 和end()。
void QFuture::cancel()
取消该 future 所代表的异步计算。请注意,取消是异步的。如果需要同步取消,请在调用 cancel() 后使用waitForFinished() 。
当前可用的结果仍可在已取消的 future 上访问,但调用此函数后,新结果将不可用。任何正在关注此 future 的QFutureWatcher 对象都不会在取消的 future 上发送进度和结果就绪信号。
请注意,并非所有正在运行的异步计算都可以取消。例如,QtConcurrent::run() 返回的 future 不能取消;但 QtConcurrent::mappedReduced() 返回的 future 可以。
template <typename U = T, typename = QtPrivate::EnableForNonVoid<U>> QFuture<T>::const_iterator QFuture::constBegin() const
返回指向未来第一个结果的 ConstSTL 样式迭代器。
template <typename U = T, typename = QtPrivate::EnableForNonVoid<U>> QFuture<T>::const_iterator QFuture::constEnd() const
返回一个常STL 样式的迭代器,指向未来最后一个结果之后的虚数结果。
另请参阅 constBegin() 和end() 。
template <typename U = T, typename = QtPrivate::EnableForNonVoid<U>> QFuture<T>::const_iterator QFuture::end() const
返回一个常STL 样式的迭代器,指向未来最后一个结果之后的虚数结果。
bool QFuture::isCanceled() const
如果使用cancel() 函数取消了异步计算,则返回true
;否则返回false
。
请注意,即使此函数返回true
,计算仍可能在运行。更多详情,请参阅cancel() 。
bool QFuture::isFinished() const
如果该 future 所代表的异步计算已经完成,则返回true
;否则返回false
。
template <typename U = T, typename = QtPrivate::EnableForNonVoid<U>> bool QFuture::isResultReadyAt(int index) const
如果index 的结果立即可用,则返回true
;否则返回false
。
另请参阅 resultAt()、resultCount() 和takeResult()。
bool QFuture::isRunning() const
如果此 future 代表的异步计算当前正在运行,则返回true
;否则返回false
。
bool QFuture::isStarted() const
如果该 future 所代表的异步计算已经启动,则返回true
;否则返回false
。
[since 6.0]
bool QFuture::isSuspended() const
如果已请求暂停异步计算,则返回true
,暂停已生效,这意味着不会再有结果或进度变化。
此函数在 Qt 6.0 中引入。
另请参阅 setSuspended()、toggleSuspended() 和isSuspending()。
[since 6.0]
bool QFuture::isSuspending() const
如果使用suspend() 函数暂停了异步计算,但工作尚未暂停,计算仍在运行,则返回true
。否则返回false
。
要检查暂停是否实际生效,请使用isSuspended() 代替。
此函数在 Qt 6.0 中引入。
另请参阅 setSuspended()、toggleSuspended() 和isSuspended()。
[since 6.0]
bool QFuture::isValid() const
如果可以从QFuture 对象访问或获取一个或多个结果,则返回true
。从未来对象获取结果后,返回 false。
此函数在 Qt 6.0 中引入。
另请参阅 takeResult()、result()、results() 和resultAt()。
[since 6.0]
template <typename Function, typename = std::enable_if_t<std::is_invocable_r_v<T, Function>>> QFuture<T> QFuture::onCanceled(Function &&handler)
将取消handler 附加到此未来。除非该未来被取消,否则返回的未来的行为与该未来完全相同(具有相同的状态和结果)。handler 是一个不带参数的可调用程序,它返回的值与此 future 封装的值类型相同。取消后,返回的 future 将打包handler 返回的值。
如果在取消前附加了处理程序,handler 将在同一线程中被调用,该线程会在取消后报告未来已完成。如果处理程序是在未来已取消后附加的,它将立即在执行onCanceled()
的线程中被调用。因此,处理程序不能总是假设将在哪个线程上运行。如果想控制在哪个线程上调用处理程序,请使用接收上下文对象的重载。
下面的示例演示了如何附加取消处理程序:
QFuture<int> testFuture = ...; auto resultFuture = testFuture.then([](int res) { // Block 1 ... return 1; }).then([](int res) { // Block 2 ... return 2; }).onCanceled([] { // Block 3 ... return -1; });
如果testFuture
被取消,Block 3
将被调用,而resultFuture
的结果将是-1
。与testFuture
不同,它不会处于Canceled
状态。这意味着您可以获取它的结果、附加计数等。
还要注意的是,您可以通过启动连续操作链的未来取消正在执行的连续操作链。假设testFuture.cancel()
被调用时,Block 1
已经在执行。下一个延续将检测到取消请求,因此Block 2
将被跳过,取消处理程序 (Block 3
) 将被调用。
注意: 此方法返回一个新的QFuture
,代表继续链的结果。取消结果QFuture
本身不会调用导致该结果的链中的取消处理程序。这意味着,如果调用resultFuture.cancel()
,也不会调用Block 3
:因为resultFuture
是将取消处理程序附加到testFuture
后产生的未来,所以resultFuture
本身没有附加取消处理程序。只有取消testFuture
或在调用onCancelled()
之前附加的延续返回的未来才能触发Block 3
。
该函数在 Qt 6.0 中引入。
[since 6.1]
template <typename Function, typename = std::enable_if_t<std::is_invocable_r_v<T, Function>>> QFuture<T> QFuture::onCanceled(QObject *context, Function &&handler)
这是一个重载函数。
将取消handler 附加到此未来,在未来被取消时调用。handler 是一个不带任何参数的可调用函数。它将在context 对象的线程中调用。如果需要在特定线程中处理取消,这将非常有用。
如果context 在链结束前被销毁,则未来将被取消。详情请参见then() 。
注: 调用此方法时,应确保context 在链的设置过程中保持存活。
有关handler 的详细信息,请参阅其他重载的文档。
此函数在 Qt 6.1 中引入。
[since 6.0]
template <typename Function, typename = std::enable_if_t<!QtPrivate::ArgResolver<Function>::HasExtraArgs>> QFuture<T> QFuture::onFailed(Function &&handler)
为该未来附加一个失败处理程序,以处理任何异常。返回的未来行为与此未来完全相同(具有相同的状态和结果),除非此未来因异常而失败。
handler 是一个不带参数或只带一个参数的可调用函数,用于过滤特定的错误类型,类似于catch语句。它返回一个由该 future 封装的类型值。失败后,返回的 future 会打包handler 返回的值。
只有当异常发生时,处理程序才会被调用。如果异常是在附加了该处理程序后发生的,那么处理程序将在因异常而报告 future 已结束的线程中执行。如果处理程序是在未来已失败后附加的,则会立即在执行onFailed()
的线程中调用。因此,处理程序不能总是假设在哪个线程上运行。如果想控制在哪个线程上调用处理程序,请使用接收上下文对象的重载。
下面的示例演示了如何附加故障处理程序:
QFuture<int> future = ...; auto resultFuture = future.then([](int res) { ... throw Error(); ... }).onFailed([](const Error &e) { // Handle exceptions of type Error ... return -1; }).onFailed([] { // Handle all other types of errors ... return -1; }); auto result = resultFuture.result(); // result is -1
如果附加了多个处理程序,则会调用与抛出异常类型匹配的第一个处理程序。例如
QFuture<int> future = ...; future.then([](int res) { ... throw std::runtime_error("message"); ... }).onFailed([](const std::exception &e) { // This handler will be invoked }).onFailed([](const std::runtime_error &e) { // This handler won't be invoked, because of the handler above. });
如果没有一个处理程序与抛出的异常类型相匹配,异常将传播到结果的未来:
QFuture<int> future = ...; auto resultFuture = future.then([](int res) { ... throw Error("message"); ... }).onFailed([](const std::exception &e) { // Won't be invoked }).onFailed([](const QException &e) { // Won't be invoked }); try { auto result = resultFuture.result(); } catch(...) { // Handle the exception }
注意: 你可以随时附加一个不带参数的处理程序,以处理所有异常类型,并避免编写 try-catch 块。
此函数在 Qt 6.0 中引入。
另请参阅 then() 和onCanceled()。
[since 6.1]
template <typename Function, typename = std::enable_if_t<!QtPrivate::ArgResolver<Function>::HasExtraArgs>> QFuture<T> QFuture::onFailed(QObject *context, Function &&handler)
这是一个重载函数。
为该 future 附加一个失败处理程序,以处理该 future 引发或已经引发的任何异常。返回一个与此 future 类型相同的QFuture 。只有在发生异常时,才会在context 对象的线程中调用该处理程序。如果需要在特定线程中处理故障,这将非常有用。例如
// somewhere in the main thread auto future = QtConcurrent::run([] { // This will run in a separate thread ... throw std::exception(); }).onFailed(this, [] { // Update UI elements });
附加到QtConcurrent::run 的故障处理程序会更新用户界面元素,因此不能在非用户界面线程中调用。因此,this
将作为.onFailed()
的上下文,以确保在主线程中调用。
如果context 在链结束前被销毁,则未来会被取消。详情请参见then() 。
注: 调用此方法时,应确保context 在链的设置过程中保持存活。
有关handler 的详细信息,请参阅其他重载的文档。
此函数在 Qt 6.1 中引入。
另请参阅 then() 和onCanceled()。
int QFuture::progressMaximum() const
返回progressValue() 的最大值。
另请参阅 progressValue() 和progressMinimum()。
int QFuture::progressMinimum() const
返回progressValue() 的最小值。
另请参阅 progressValue() 和progressMaximum()。
QString QFuture::progressText() const
返回异步计算所报告的进度文本(可选)。
请注意,并非所有计算都提供进度的文本表示,因此此函数可能返回空字符串。
int QFuture::progressValue() const
返回当前进度值,介于progressMinimum() 和progressMaximum() 之间。
另请参阅 progressMinimum() 和progressMaximum()。
template <typename U = T, typename = QtPrivate::EnableForNonVoid<U>> T QFuture::result() const
返回未来的第一个结果。如果结果不是立即可用,该函数将阻塞并等待结果可用。这是一种方便的方法,用于调用resultAt(0)。请注意,result()
返回的是内部存储结果的副本。如果T
是只允许移动的类型,或者您不想复制结果,请使用takeResult() 代替。
另请参阅 resultAt()、results() 和takeResult()。
template <typename U = T, typename = QtPrivate::EnableForNonVoid<U>> T QFuture::resultAt(int index) const
返回index 的结果。如果结果不是立即可用,该函数将阻塞并等待结果可用。
另请参阅 result()、results()、takeResult() 和resultCount()。
int QFuture::resultCount() const
返回未来可用的连续结果数。由于结果集中存在间隙,存储结果的实际数量可能与此值不同。从 0 到 resultCount() 之间遍历结果始终是安全的。
另请参阅 result()、resultAt()、results() 和takeResult()。
template <typename U = T, typename = QtPrivate::EnableForNonVoid<U>> QList<T> QFuture::results() const
返回未来的所有结果。如果结果不是立即可用,该函数将阻塞并等待结果可用。请注意,results()
返回的是内部存储结果的副本。目前不支持获取只移动类型T
的所有结果。不过,您仍然可以使用STL 风格的迭代器或Java 风格的只读迭代器遍历只移动结果列表。
另请参见 result()、resultAt()、takeResult()、resultCount() 和isValid()。
void QFuture::resume()
恢复 future() 所代表的异步计算。这是一个方便的方法,只需调用setSuspended(false)。
另请参阅 suspend().
[since 6.0]
void QFuture::setSuspended(bool suspend)
如果suspend 为 true,该函数将暂停 future() 所代表的异步计算。如果计算已经暂停,则此函数不会执行任何操作。当 future 被暂停时,QFutureWatcher 不会立即停止发送进度和结果就绪信号。在暂停的时刻,可能仍有正在进行的计算无法停止。这些计算的信号仍将被发送。
如果suspend 为 false,此函数将恢复异步计算。如果之前没有暂停计算,则此函数不会执行任何操作。
请注意,并非所有计算都可以暂停。例如,QtConcurrent::run() 返回的QFuture 不能被暂停;但 QtConcurrent::mappedReduced() 返回的QFuture 可以被暂停。
该函数在 Qt 6.0 中引入。
另请参阅 isSuspended()、suspend()、resume() 和toggleSuspended() 。
[since 6.0]
void QFuture::suspend()
暂停此 future 所代表的异步计算。这是一个方便的方法,只需调用setSuspended(true)。
此函数在 Qt 6.0 中引入。
另请参阅 resume()。
[since 6.0]
template <typename U = T, typename = QtPrivate::EnableForNonVoid<U>> T QFuture::takeResult()
只有当isValid() 返回true
时才调用该函数,否则行为未定义。当预期只有一个结果时,该函数从QFuture 对象中获取(移动)第一个结果。如果还有其他结果,则在获取第一个结果后将其丢弃。如果结果不是立即可用,该函数将阻塞并等待结果可用。QFuture 将尽可能使用移动语义,如果类型不可移动,将退回到复制结构。在得到结果后,isValid() 将作为false
进行评估。
QFuture QFuture takeResult ()的引入是为了让QFuture 也能处理只可移动的类型(如 std::unique_ptr),因此它假定只有一个线程可以将结果从未来移出,而且只做一次。还要注意的是,目前还不支持获取所有结果的列表。不过,您仍然可以使用STL 风格的迭代器或Java 风格的只读迭代器遍历只移动结果的列表。
此函数在 Qt 6.0 中引入。
另请参阅 result()、results()、resultAt() 和isValid()。
[since 6.0]
template <typename Function> QFuture<QFuture<T>::ResultType<Function>> QFuture::then(Function &&function)
这是一个重载函数。
Sync function 是一个可调用的函数,如果有结果(不是 <void>),它将接收一个由该 future 封装的类型的参数。否则,它不需要任何参数。此方法返回一个新的 ,它封装了一个由 返回类型的值。返回的 future 将处于未初始化状态,直到所附的延续被调用,或这个 future 失败或被取消。QFuture QFuture function
注: 如果需要在单独的线程中启动延续,请使用此方法的其他重载。
您可以像这样链式执行多个操作:
QFuture<int> future = ...; future.then([](int res1){ ... }).then([](int res2){ ... })...
或者
QFuture<void> future = ...; future.then([](){ ... }).then([](){ ... })...
Continuation 也可以接受一个QFuture 参数(而不是其值),代表前一个 future。举例来说,如果QFuture 有多个结果,而用户希望在继续操作中访问这些结果,这就非常有用。或者,用户需要在继续程序中处理前一个未来的异常,以避免中断多个继续程序链。例如
QFuture<int> future = ...; future.then([](QFuture<int> f) { try { ... auto result = f.result(); ... } catch (QException &e) { // handle the exception } }).then(...);
如果前一个未来程序抛出了异常,并且没有在继续程序中处理,那么异常将传播到继续未来程序,以便调用者处理:
QFuture<int> future = ...; auto continuation = future.then([](int res1){ ... }).then([](int res2){ ... })... ... // future throws an exception try { auto result = continuation.result(); } catch (QException &e) { // handle the exception }
在这种情况下,整个继续链将被中断。
注意: 如果此 future 被取消,与其相连的连续过程也将被取消。
此函数在 Qt 6.0 中引入。
另请参阅 onFailed() 和onCanceled()。
[since 6.1]
template <typename Function> QFuture<QFuture<T>::ResultType<Function>> QFuture::then(QObject *context, Function &&function)
这是一个重载函数。
将一个延续附加到此 future,以便在需要时链式执行多个异步计算。当该 future 所代表的异步计算完成后,function 将在context 对象的线程中调用。如果需要在特定线程中调用延续,这将非常有用。例如
// somewhere in the main thread auto future = QtConcurrent::run([] { // This will run in a separate thread ... }).then(this, [] { // Update UI elements });
附加到QtConcurrent::run 中的延续会更新用户界面元素,因此不能在非 gui 线程中调用。因此,this
将作为.then()
的上下文,以确保在主线程中调用。
除非指定了不同的上下文或启动策略,否则也将在同一上下文中调用以下继续程序:
auto future = QtConcurrent::run([] { ... }).then(this, [] { // Update UI elements }).then([] { // This will also run in the main thread });
这是因为默认情况下,.then()
与前一个程序在同一线程中调用。
但要注意的是,如果在这个 future 已经结束后才附加该延续,那么它将立即在执行then()
的线程中被调用:
QObject *context = ...; auto future = cachedResultsReady ? QtFuture::makeReadyValueFuture(result) : QtConcurrent::run([] { /* compute result */}); auto continuation = future.then(context, [] (Result result) { // Runs in the context's thread }).then([] { // May or may not run in the context's thread });
在上述示例中,如果cachedResultsReady
是true
,并且返回了一个就绪的未来,那么第一个.then()
有可能在第二个未来被附加之前就已完成。在这种情况下,它将在当前线程中解决。因此,如有疑问,请明确传递上下文。
如果context 在链结束前被销毁,则未来会被取消。这意味着当context 不再有效时,可能会调用取消处理程序。为防止出现这种情况,可将context 作为QPointer 捕捉:
QObject *context = ...; auto future = ...; auto continuation = future.then(context, [context](Result result) { // ... }).onCanceled([context = QPointer(context)] { if (!context) return; // context was destroyed already // handle cancellation });
当上下文对象被销毁时,取消会立即发生。链中的前一个期货不会被取消,而是继续运行直到结束。
注: 调用此方法时,应确保context 在链的设置过程中保持存活。
此函数在 Qt 6.1 中引入。
另请参阅 onFailed() 和onCanceled()。
[since 6.0]
template <typename Function> QFuture<QFuture<T>::ResultType<Function>> QFuture::then(QThreadPool *pool, Function &&function)
这是一个重载函数。
为该 future 附加一个延续,以便在需要时连锁多个异步计算。当该 future 所代表的异步计算完成时,function 将被调度到pool 。
此函数在 Qt 6.0 中引入。
另请参阅 onFailed() 和onCanceled()。
[since 6.0]
template <typename Function> QFuture<QFuture<T>::ResultType<Function>> QFuture::then(QtFuture::Launch policy, Function &&function)
这是一个重载函数。
为该 future 附加一个延续,从而可以链式执行多个异步计算。当该 future 所代表的异步计算结束时,function 将根据给定的启动policy 被调用。会返回一个新的QFuture ,代表继续的结果。
根据policy ,继续将在与此 future 相同的线程、新线程或继承此 future 的启动策略和线程池中调用。如果没有指定启动策略(请参阅重载只接收一个可调用代码),则将使用Sync
策略。
在下面的示例中,两个连续程序都将在新线程(但在同一个线程)中调用。
QFuture<int> future = ...; future.then(QtFuture::Launch::Async, [](int res){ ... }).then([](int res2){ ... });
在下面的示例中,两个连续函数都将在使用同一线程池的新线程中调用。
QFuture<int> future = ...; future.then(QtFuture::Launch::Async, [](int res){ ... }) .then(QtFuture::Launch::Inherit, [](int res2){ ... });
有关function 的更多详情,请参阅其他重载的文档。
该函数在 Qt 6.0 中引入。
另请参阅 onFailed() 和onCanceled()。
[since 6.0]
void QFuture::toggleSuspended()
切换异步计算的暂停状态。换句话说,如果计算当前处于暂停或中止状态,则调用此函数可恢复计算;如果计算正在运行,则处于暂停状态。这是调用setSuspended(!(isSuspending() ||isSuspended())) 的便捷方法。
该函数在 Qt 6.0 中引入。
另请参阅 setSuspended()、suspend() 和resume()。
[since 6.4]
template <typename U> QFuture<U> QFuture::unwrap()
从QFuture<T>
解绑内部未来,其中T
是一个类型为QFuture<U>
的未来,即这个未来的类型为QFuture<QFuture<U>>
。举例来说,当嵌套在 内的内部未来被执行时,内部未来也将被执行:
unwrappedFuture
一旦嵌套在 中的内部将来时执行完毕,就会立即执行,并在报告内部将来时执行完毕的同一线程中出现相同的结果或异常。如果内部 future 被取消, 也会被取消。outerFuture
unwrappedFuture
当多个计算发生链式反应,且其中一个计算返回的结果类型是QFuture
时,这一点尤其有用。例如,假设我们想从 URL 下载多张图片,缩放图片,并使用 QtConcurrent::mappedReduced() 将其还原为单张图片。我们可以这样写
auto downloadImages = [] (const QUrl &url) { QList<QImage> images; ... return images; }; auto processImages = [](const QList<QImage> &images) { return QtConcurrent::mappedReduced(images, scale, reduceImages); } auto show = [](const QImage &image) { ... }; auto future = QtConcurrent::run(downloadImages, url) .then(processImages) .unwrap() .then(show);
这里QtConcurrent::mappedReduced()
返回一个QFuture<QImage>
,所以.then(processImages)
返回一个QFuture<QFuture<QImage>>
。由于show()
将QImage
作为参数,所以.then(processImages)
的结果不能直接传给它。我们需要调用.unwrap()
,它将在准备就绪时获取内部 future 的结果,并将其传递给下一个延续。
在多重嵌套的情况下,.unwrap()
会向下传递到最内层:
该函数在 Qt 6.4 中引入。
void QFuture::waitForFinished()
等待异步计算结束(包括cancel()ed 计算),即直到isFinished() 返回true
。
QFuture<T> &QFuture::operator=(const QFuture<T> &other)
将other 赋值给此 future,并返回此 future 的引用。
© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.