From dfaca09e85a49d2983bb89893bfbe1ba4c19eab4 Mon Sep 17 00:00:00 2001 From: Sona Kurazyan Date: Thu, 27 Feb 2020 17:30:07 +0100 Subject: Add support for attaching continuations to QFuture MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added QFuture::then() methods to allow chaining multiple asynchronous computations. Continuations can use the following execution policies: * QtFuture::Launch::Sync - the continuation will be launched in the same thread in which the parent has been executing. * QtFuture::Launch::Async - the continuation will be launched in a new thread. * QtFuture::Launch::Inherit - the continuation will inherit the launch policy of the parent, or its thread pool (if it was using a custom one). * Additionally then() also accepts a custom QThreadPool* instance. Note, that if the parent future gets canceled, its continuation(s) will be also canceled. If the parent throws an exception, it will be propagated to the continuation's future, unless it is caught inside the continuation (if it has a QFuture arg). Some example usages: QFuture future = ...; future.then([](int res1){ ... }).then([](int res2){ ... })... QFuture future = ...; future.then([](QFuture fut1){ /* do something with fut1 */ })... In the examples above all continuations will run in the same thread as future. QFuture future = ...; future.then(QtFuture::Launch::Async, [](int res1){ ... }) .then([](int res2){ ... }).. In this example the continuations will run in a new thread (but on the same one). QThreadPool pool; QFuture future = ...; future.then(&pool, [](int res1){ ... }) .then([](int res2){ ... }).. In this example the continuations will run in the given thread pool. [ChangeLog][QtCore] Added support for attaching continuations to QFuture. Task-number: QTBUG-81587 Change-Id: I5b2e176694f7ae8ce00404aca725e9a170818955 Reviewed-by: Leena Miettinen Reviewed-by: Timur Pocheptsov Reviewed-by: MÃ¥rten Nordheim --- src/corelib/thread/qfutureinterface.cpp | 50 ++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 4 deletions(-) (limited to 'src/corelib/thread/qfutureinterface.cpp') diff --git a/src/corelib/thread/qfutureinterface.cpp b/src/corelib/thread/qfutureinterface.cpp index e6380a8732..074e28d8df 100644 --- a/src/corelib/thread/qfutureinterface.cpp +++ b/src/corelib/thread/qfutureinterface.cpp @@ -191,6 +191,11 @@ bool QFutureInterfaceBase::isResultReadyAt(int index) const return d->internal_isResultReadyAt(index); } +bool QFutureInterfaceBase::isRunningOrPending() const +{ + return queryState(static_cast(Running | Pending)); +} + bool QFutureInterfaceBase::waitForNextResult() { QMutexLocker lock(&d->m_mutex); @@ -315,7 +320,7 @@ void QFutureInterfaceBase::waitForResult(int resultIndex) d->m_exceptionStore.throwPossibleException(); QMutexLocker lock(&d->m_mutex); - if (!isRunning()) + if (!isRunningOrPending()) return; lock.unlock(); @@ -326,7 +331,7 @@ void QFutureInterfaceBase::waitForResult(int resultIndex) lock.relock(); const int waitIndex = (resultIndex == -1) ? INT_MAX : resultIndex; - while (isRunning() && !d->internal_isResultReadyAt(waitIndex)) + while (isRunningOrPending() && !d->internal_isResultReadyAt(waitIndex)) d->waitCondition.wait(&d->m_mutex); d->m_exceptionStore.throwPossibleException(); @@ -335,7 +340,7 @@ void QFutureInterfaceBase::waitForResult(int resultIndex) void QFutureInterfaceBase::waitForFinished() { QMutexLocker lock(&d->m_mutex); - const bool alreadyFinished = !isRunning(); + const bool alreadyFinished = !isRunningOrPending(); lock.unlock(); if (!alreadyFinished) { @@ -343,7 +348,7 @@ void QFutureInterfaceBase::waitForFinished() lock.relock(); - while (isRunning()) + while (isRunningOrPending()) d->waitCondition.wait(&d->m_mutex); } @@ -386,6 +391,11 @@ void QFutureInterfaceBase::setThreadPool(QThreadPool *pool) d->m_pool = pool; } +QThreadPool *QFutureInterfaceBase::threadPool() const +{ + return d->m_pool; +} + void QFutureInterfaceBase::setFilterMode(bool enable) { QMutexLocker locker(&d->m_mutex); @@ -604,4 +614,36 @@ void QFutureInterfaceBasePrivate::setState(QFutureInterfaceBase::State newState) state.storeRelaxed(newState); } +void QFutureInterfaceBase::setContinuation(std::function func) +{ + QMutexLocker lock(&d->continuationMutex); + // If the state is ready, run continuation immediately, + // otherwise save it for later. + if (isFinished()) { + lock.unlock(); + func(); + } else { + d->continuation = std::move(func); + } +} + +void QFutureInterfaceBase::runContinuation() const +{ + QMutexLocker lock(&d->continuationMutex); + if (d->continuation) { + lock.unlock(); + d->continuation(); + } +} + +void QFutureInterfaceBase::setLaunchAsync(bool value) +{ + d->launchAsync = value; +} + +bool QFutureInterfaceBase::launchAsync() const +{ + return d->launchAsync; +} + QT_END_NAMESPACE -- cgit v1.2.3