Details
-
Bug
-
Resolution: Fixed
-
P2: Important
-
6.8.0
-
None
-
25
-
cdc71532e (dev), 3164746eb (dev), b0e82f598 (dev)
-
Foundation Sprint 124, Foundation Sprint 125
Description
QFuture::cancel() behaves unintuitively and is impractical when used in conjunction with continuation chains.
Specifically, there's no obvious way to cancel such a chain. Suppose we have:
auto f = foo() .then(...) // a .then(...) // b .then(...) // c .then(...); // d
Calling f.cancel() will only cancel the very last continuation (`d`), nothing else. This is contrary to basic expectations - I'd expect every not-yet-finished continuation to be canceled as well. It's also not documented.
Having read the impl of QFutureInterfaceBase::cancel(), I thought that I could maybe cancel() the very first future:
auto f = foo(); auto firstF = f; f = f .then(...) // a .then(...) // b .then(...) // c .then(...); // d firstF.cancel();
But that only works when `firstF` has not yet finished! If it is finished already by the time I cancel it, nothing happens and the chain runs to the end.
In the end, I have to keep a list of all intermediate futures and cancel each one in order to reliably cancel the chain:
QList<QFuture<void>> futures; auto f = foo(); futures << f; f = f.then(...) // a futures << f; f = f.then(...) // b futures << f; f = f.then(...) // c futures << f; f = f.then(...); // d futures << f; for (auto &f : futures) { f.cancel(); }
This is super inconvenient (and unexpected).
It would be cool if there was an overload to forcibly cancel the whole chain that a future belongs to.
Reproduction
QPromise<void> p1, p2; p1.start(); p2.start(); auto f = QtFuture::makeReadyVoidFuture() .then([f = p1.future()]() { qDebug() << "Init"; return f; }).unwrap().then([f = p2.future()]() { qDebug() << "Continue1"; return f; }).unwrap().then([&]{ qDebug() << "Continue2"; }).onCanceled([] { qDebug() << "Cancelled"; }); p1.finish(); f.cancel(); p2.finish();
Expected output:
Init Continue1 Cancelled
Actual output:
Init Continue1 Continue2
Note: Is the problem actually the nested and unwrapped futures?
Attachments
For Gerrit Dashboard: QTBUG-130662 | ||||||
---|---|---|---|---|---|---|
# | Subject | Branch | Project | Status | CR | V |
620490,12 | QFutureInterfaceBase: rework setContinuation() overload set | dev | qt/qtbase | Status: MERGED | +2 | 0 |
620838,8 | QFutureInterface: mark the unused setContinuation() overloads as removed | dev | qt/qtbase | Status: MERGED | +2 | 0 |
620899,9 | Add QFuture::cancelChain() | dev | qt/qtbase | Status: MERGED | +2 | 0 |