QFutureInterface: add a warning when an existing continuation is overwritten

... and also extend the documentation to explain this case explicitly.

Fixes: QTBUG-107545
Change-Id: I9414cc677b037989de60e97871485018e5c8a569
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
(cherry picked from commit 502a7706b94380d4957a7e594fc7c4c4db8ae81b)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Ivan Solovev 2023-03-09 13:22:12 +01:00 committed by Qt Cherry-pick Bot
parent 122c825022
commit 2e1025dd4a
4 changed files with 57 additions and 0 deletions

View File

@ -385,3 +385,17 @@ QFuture<QFuture<QFuture<int>>>> outerFuture;
QFuture<int> unwrappedFuture = outerFuture.unwrap();
//! [30]
//! [31]
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();
//! [31]

View File

@ -75,6 +75,15 @@
If \c testFuture gets canceled, its state is propagated to the next then(),
which will be also canceled. So in this case \c {Block 6} will be called.
The future can have only one continuation. Consider the following example:
\snippet code/src_corelib_thread_qfuture.cpp 31
In this case \c f1 and \c f2 are effectively the same QFuture object, as
they share the same internal state. As a result, calling
\l {QFuture::}{then} on \c f2 will overwrite the continuation specified for
\c {f1}. So, only \c {"second"} will be printed when this code is executed.
QFuture also offers ways to interact with a running computation. For
instance, the computation can be canceled with the cancel() function. To
suspend or resume the computation, use the setSuspended() function or one of

View File

@ -834,6 +834,10 @@ void QFutureInterfaceBase::setContinuation(std::function<void(const QFutureInter
// store the move-only continuation, to guarantee that the associated
// future's data stays alive.
if (d->continuationState != QFutureInterfaceBasePrivate::Cleaned) {
if (d->continuation) {
qWarning() << "Adding a continuation to a future which already has a continuation. "
"The existing continuation is overwritten.";
}
d->continuation = std::move(func);
d->continuationData = continuationFutureData;
}

View File

@ -220,6 +220,7 @@ private slots:
void whenAnyDifferentTypesWithCanceled();
void whenAnyDifferentTypesWithFailed();
void continuationOverride();
void continuationsDontLeak();
void cancelAfterFinishWithContinuations();
@ -4662,6 +4663,35 @@ void tst_QFuture::whenAnyDifferentTypesWithFailed()
#endif
}
void tst_QFuture::continuationOverride()
{
QPromise<int> p;
bool firstExecuted = false;
bool secondExecuted = false;
QTest::ignoreMessage(QtWarningMsg,
"Adding a continuation to a future which already has a continuation. "
"The existing continuation is overwritten.");
QFuture<int> f1 = p.future();
f1.then([&firstExecuted](int) {
firstExecuted = true;
});
QFuture<int> f2 = p.future();
f2.then([&secondExecuted](int) {
secondExecuted = true;
});
p.start();
p.addResult(42);
p.finish();
QVERIFY(p.future().isFinished());
QVERIFY(!firstExecuted);
QVERIFY(secondExecuted);
}
struct InstanceCounter
{
InstanceCounter() { ++count; }