Fix QFuture::waitForFinished to wait until QFuture is started

Currently QFuture::waitForFinished() exits as soon as the future is not
in the running state. If the user calls it before
QPromise::reportStarted() is called, it will exit immediately, because
nothing is running yet. Fix the behavior to wait for the finished state.

[ChangeLog][Important Behavior Changes][QtCore] Fixed the behavior of
QFuture::waitForFinished() to wait until the future is actually in the
finished state, instead of exiting as soon as it is not in the running
state. This prevents waitForFinished() from exiting immediately, if at
the moment of calling it the future is not started yet.

Task-number: QTBUG-84867
Change-Id: I12f5e95d8200cfffa5653b6aa566a625f8320ca8
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
Sona Kurazyan 2020-08-24 16:57:18 +02:00
parent 7d35e31efb
commit 9efe2a8603
5 changed files with 30 additions and 8 deletions

View File

@ -404,7 +404,7 @@
/*! \fn template <typename T> void QFuture<T>::waitForFinished()
Waits for the asynchronous computation to finish (including cancel()ed
computations).
computations), i.e. until isFinished() returns \c true.
*/
/*! \fn template <typename T> T QFuture<T>::result() const

View File

@ -422,7 +422,7 @@ void QFutureInterfaceBase::waitForResult(int resultIndex)
void QFutureInterfaceBase::waitForFinished()
{
QMutexLocker lock(&d->m_mutex);
const bool alreadyFinished = !isRunningOrPending();
const bool alreadyFinished = isFinished();
lock.unlock();
if (!alreadyFinished) {
@ -430,7 +430,7 @@ void QFutureInterfaceBase::waitForFinished()
lock.relock();
while (isRunningOrPending())
while (!isFinished())
d->waitCondition.wait(&d->m_mutex);
}

View File

@ -417,7 +417,7 @@ bool QFutureWatcherBase::isSuspended() const
/*! \fn template <typename T> void QFutureWatcher<T>::waitForFinished()
Waits for the asynchronous computation to finish (including cancel()ed
computations).
computations), i.e. until isFinished() returns \c true.
*/
void QFutureWatcherBase::waitForFinished()
{

View File

@ -144,6 +144,7 @@ private slots:
void takeResultWorksForTypesWithoutDefaultCtor();
void canceledFutureIsNotValid();
void signalConnect();
void waitForFinished();
private:
using size_type = std::vector<int>::size_type;
@ -3076,5 +3077,29 @@ void tst_QFuture::signalConnect()
}
}
void tst_QFuture::waitForFinished()
{
QFutureInterface<void> fi;
auto future = fi.future();
QScopedPointer<QThread> waitingThread (QThread::create([&] {
future.waitForFinished();
}));
waitingThread->start();
QVERIFY(!waitingThread->wait(200));
QVERIFY(!waitingThread->isFinished());
fi.reportStarted();
QVERIFY(!waitingThread->wait(200));
QVERIFY(!waitingThread->isFinished());
fi.reportFinished();
QVERIFY(waitingThread->wait());
QVERIFY(waitingThread->isFinished());
}
QTEST_MAIN(tst_QFuture)
#include "tst_qfuture.moc"

View File

@ -75,11 +75,8 @@ void snippet_QPromise::basicExample()
QPromise<int> promise;
QFuture<int> future = promise.future();
// Note: calling reportStarted() prior to thread creation to enforce order
// of calls: first promise.reportStarted() then future.waitForFinished()
promise.reportStarted(); // notifies QFuture that the computation is started
QScopedPointer<QThread> thread(QThread::create([] (QPromise<int> promise) {
promise.reportStarted(); // notifies QFuture that the computation is started
promise.addResult(42);
promise.reportFinished(); // notifies QFuture that the computation is finished
}, std::move(promise)));