[Development] QPromise cancellation

Arno Rehn a.rehn at menlosystems.com
Wed Jan 28 11:26:17 CET 2026


Hey everyone,

Context: I'm currently working on making QFuture/QPromise compatible 
with C++20 coroutine syntax: https://gitlab.com/pumphaus/qawaitablefuture/
This works really nicely already and when finished I'd like to upstream 
this into Qt proper.

In this context, I've stumbled on propagating cancellation of a QFuture. 
Cancellation is supported by means of QFuture::cancel(). Initially, this 
only sets a flag in the shared state. A long-running task can check 
QPromise::isCanceled() and abort at suitable moments, calling 
QPromise::finish(). QFuture::onCanceled() handlers will only run when 
the future is canceled *and* finished.

This becomes interesting when you have nested and/or chained QFutures. 
Since Qt 6.10 we have QFuture::cancelChain() which propagates the 
"canceled" flag up a continuation chain (nice!). But we don't yet have a 
solution for propagating cancelation into nested futures. Think:

     auto f = task().then([]{ return someOtherTask(); }).unwrap().

Calling f.cancel() while someOtherTask() is running will not have any 
effect. someOtherTask() will not have the canceled flag set and will not 
be notified of cancelation whatsoever. Naively, we'd need some kind of 
callback for "this was canceled" that we can attach to and propagate 
this to inner futures, akin to

     auto unwrap() {
         // ...
         outerFuture.cancelCallback = [=] { innerFuture.cancelChain(); };
     }

This kind of callback actually exists already in the form of 
QFutureWatcher/QFutureCallOutInterface. In a proof-of-concept in my 
"qawaitablefuture" this even works nicely. But the overhead of creating 
a QObject for every unwrap()/coroutine seems too high. We could use 
QFutureCallOutInterface directly, but this still feels "dirty". The 
CallOutInterface was specifically made for QFutureWatcher; continuations 
disregard it completely. Using QFutureCallOutInterface for this now 
feels like mixing two systems that were not ever designed to work 
together. And we'd just pile more and more things on in the internals of 
QFuture, which already are quite a mess trying to fit multiple and 
"weird" use cases (looking at you, "multiple result QFuture").

Looking at how others do it: they don't ingrain cancelation into their 
promise types at all (JS, C++ stdlib). Instead, if you want something to 
support cancelation, you explicitly pass down a token of sorts, like 
https://en.cppreference.com/w/cpp/header/stop_token.html. Propagation of 
the cancelation flag is now explicit and orthogonal to continuations, 
making for an overall nicer design I think. OTOH, we have what we have 
in Qt, so it would make sense to at least make it usable without any 
footguns.

Opinions?

Cheers,
Arno

-- 
Arno Rehn
Principal Software Engineer
Tel +49 89 189 166 0
Fax +49 89 189 166 111
a.rehn at menlosystems.com
www.menlosystems.com

Menlo Systems GmbH
Bunsenstrasse 5, D-82152 Martinsried, Germany
Amtsgericht München HRB 138145
Geschäftsführung: Dr. Michael Mei, Dr. Ronald Holzwarth
USt.-IdNr. DE217772017, St.-Nr. 14316170324



More information about the Development mailing list