Date: Tue, 14 Apr 2026 12:05:26 +0200
There's plenty of coroutine frameworks out there with cancellation
built-in, but I'd like it to be part of the C++ standard, not yet another
library someone must include to be able to use the C++ coroutines.
Currently, people have no choice but to:
A) implement their own promise types (with all of the required knowledge
potentially being a problem), or
B) Rely on external libraries
C++20 introduced coroutines, so I find it pretty natural that the next step
is to also provide a standardized way to use coroutines rather than
just providing the framework.
Op zo 12 apr 2026 om 14:35 schreef Zhao YunShan via Std-Proposals <
std-proposals_at_[hidden]>:
>
> I can provide a comprehensive solution, a complete coroutine framework.
> You can find the source code [https://github.com/dou1984/coev.git]
> Key features include:
>
> 1. A co_event that supports manual suspension and resumption, giving
> you full control!!!
> 2. wait_for_all, wait_for_any, and co_task primitives.
>
> Based on your requirements, I can also provide some pseudocode for
> reference.
>
> class Router
> {
> std::map<int , co_event> m_cancellation;
>
> awaitable<int> handle_message(session& sess)
> {
> auto& cancel = m_cancellation[sess->Id()];
> defer(m_cancellation.erase(sess->id());
>
> auto client = co_await g_client_pool.get();
> defer(client.release(client));
>
> co_task _task;
> auto request_id = _task << [](auto& client) -> awaitable<void>
> {
> auto r = client.request(...);
> if (r == INVALID)
> {
> LOG(...);
> }
> }(client);
>
> auto cancel_id = _task << [](auto& cancel) -> awaitable<void>
> {
> co_await cancel.suspend();
> }(cancel);
>
> auto ret_id = co_await _task.wait();
> if (ret_id == cancel_id)
> {
> LOG("cancel");
> co_return INVALID;
> }
>
> LOG("success");
> return 0;
> }
> void cancel(int id)
> {
> if (auto it = m_cancellation.find(id); it != m_cancellation.end())
> {
> it->second.resume();
> }
> }
> };
>
> >Date: Thu, 9 Apr 2026 15:23:23 +0100
> >From: L?n?rd Szolnoki <cpp_at_[hidden]>
> >To: std-proposals_at_[hidden]
> >Subject: Re: [std-proposals] Automatic Coroutine Cancellation
> >Message-ID: <a94be06c-ec0a-444c-8982-c1f6511e1921_at_[hidden]>
> >Content-Type: text/plain; charset=UTF-8; format=flowed
> >
> >
> >
> >On 09/04/2026 14:42, Arthur O'Dwyer via Std-Proposals wrote:
> >> On Sat, Apr 4, 2026 at 5:04?AM Rhidian De Wit via Std-Proposals <std-
> >> proposals_at_[hidden] <mailto:std-proposals_at_[hidden]>> wrote:
> >>
> >>
> >> I've been reading up a bit on C++26 std::execution and I noticed that for cancellation
> >> we still use the `std::stop_token` approach to be able to "cancel" a coroutine by
> >> forcing the user to always call `stop_requested()` before continuing the coroutine, in
> >> addition to needing to pass a `std::stop_source` or `std::stop_token` around, making
> >> it pretty inconvenient to use.
> >>
> >> Now, there are ways to make this more automatic, for example, by embedding the
> >> `std::stop_source` in the coroutine's?promise type and checking at every suspension /
> >> resumption point (`await_suspend()` and `await_resume()` respectfully) whether or not
> >> the coroutine has been cancelled. If so, you can throw an exception and let the
> >> coroutine unwind itself.
> >>
> >> I was wondering if there is a proposal for such an automatic cancellation feature in
> >> the works or already present?
> >>
> >>
> >> I am relatively uneducated in this area; but no, I'm not aware of any plan or proposal to
> >> embed a stop_token into every coroutine.
> >> My kneejerk reaction was "That sounds bad! Every suspend point would become an invisible
> >> interruption point ? you couldn't hold a resource across a suspend point without careful
> >> planning!"
> >> But then I thought again, and realized that we already have /that/. The caller is the one
> >> who decides whether to resume a coroutine_handle<>; if the caller decides to destroy() it
> >> instead, well, that suspend point just turned into an invisible abort anyway, from the
> >> coroutine's?point of view.
> >> Example of safely holding a resource across a suspend: https://godbolt.org/z/azTW57qf8
> >> <https://godbolt.org/z/azTW57qf8>
> >> Example of unsafely (leakily) holding the same: https://godbolt.org/z/f4rTG7Kh3 <https://
> >> godbolt.org/z/f4rTG7Kh3>
> >>
> >> But then I'm afraid I don't understand what feature you're asking for. You can already
> >> "tell a coroutine to unwind itself" by just destroying the handle you were using to talk
> >> to it. Why would you also need a stop_token/stop_source to be involved? Are you trying to
> >> stop someone /else's/ coroutine, like from another thread, without the participation of
> >> its owner? But then what do you expect the coroutine to do ? report .done() despite not
> >> having reached the co_return statement, I guess? Which means what ? call .final_suspend()
> >> on the promise without having first called either `.return_value()` or `.return_void()`?
> >> Is that something that's possible to do today (except manually)? Why would I want that?
> >> In particular, adding the ability for the compiler to generate a new and unusual?sequence
> >> of calls to my promise type means suddenly there's a lot more surface area I'd?need to
> >> cover in my promise types' unit tests to make sure they're not buggy/leaky even in this
> >> new special case.
> >
> >For precedence, python's asyncio has the exception model for cancellation (an exception of
> >type asyncio.CancelledError from a suspension point when a task is cancelled).
> >
> >One thing it allows is to have asynchronous teardown logic, like gracefully terminating
> >network sessions, deregistering from mDNS (zeroconf), etc... .
> >
> >In comparison simply "dropping" the coroutine (destroying the handle) forces the teardown
> >to be either synchronous, or schedule teardown tasks elsewhere, but it's unclear to me
> >where tasks scheduled from the destruction of coroutines can be cleanly joined. From what
> >I heard Rust (or tokio?) has this cancellation model, but I can't comment on that.
> >
> >I know very little about std::execution to comment on that. My gut feeling is that
> >exceptions are too heavy for C++ for a general cancellation solution (but I agree that it
> >is ergonomic, I use it with ASIO), the stop_token is probably sufficiently light, but
> >verbose to use, and just dropping coroutines is missing out on async teardown.
> >
> >I wish herbceptions were pursued, I think herbception cancellation in coroutines would hit
> >the sweet spot.
> >
> >Cheers,
> >L?n?rd
> >
>
>
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>
built-in, but I'd like it to be part of the C++ standard, not yet another
library someone must include to be able to use the C++ coroutines.
Currently, people have no choice but to:
A) implement their own promise types (with all of the required knowledge
potentially being a problem), or
B) Rely on external libraries
C++20 introduced coroutines, so I find it pretty natural that the next step
is to also provide a standardized way to use coroutines rather than
just providing the framework.
Op zo 12 apr 2026 om 14:35 schreef Zhao YunShan via Std-Proposals <
std-proposals_at_[hidden]>:
>
> I can provide a comprehensive solution, a complete coroutine framework.
> You can find the source code [https://github.com/dou1984/coev.git]
> Key features include:
>
> 1. A co_event that supports manual suspension and resumption, giving
> you full control!!!
> 2. wait_for_all, wait_for_any, and co_task primitives.
>
> Based on your requirements, I can also provide some pseudocode for
> reference.
>
> class Router
> {
> std::map<int , co_event> m_cancellation;
>
> awaitable<int> handle_message(session& sess)
> {
> auto& cancel = m_cancellation[sess->Id()];
> defer(m_cancellation.erase(sess->id());
>
> auto client = co_await g_client_pool.get();
> defer(client.release(client));
>
> co_task _task;
> auto request_id = _task << [](auto& client) -> awaitable<void>
> {
> auto r = client.request(...);
> if (r == INVALID)
> {
> LOG(...);
> }
> }(client);
>
> auto cancel_id = _task << [](auto& cancel) -> awaitable<void>
> {
> co_await cancel.suspend();
> }(cancel);
>
> auto ret_id = co_await _task.wait();
> if (ret_id == cancel_id)
> {
> LOG("cancel");
> co_return INVALID;
> }
>
> LOG("success");
> return 0;
> }
> void cancel(int id)
> {
> if (auto it = m_cancellation.find(id); it != m_cancellation.end())
> {
> it->second.resume();
> }
> }
> };
>
> >Date: Thu, 9 Apr 2026 15:23:23 +0100
> >From: L?n?rd Szolnoki <cpp_at_[hidden]>
> >To: std-proposals_at_[hidden]
> >Subject: Re: [std-proposals] Automatic Coroutine Cancellation
> >Message-ID: <a94be06c-ec0a-444c-8982-c1f6511e1921_at_[hidden]>
> >Content-Type: text/plain; charset=UTF-8; format=flowed
> >
> >
> >
> >On 09/04/2026 14:42, Arthur O'Dwyer via Std-Proposals wrote:
> >> On Sat, Apr 4, 2026 at 5:04?AM Rhidian De Wit via Std-Proposals <std-
> >> proposals_at_[hidden] <mailto:std-proposals_at_[hidden]>> wrote:
> >>
> >>
> >> I've been reading up a bit on C++26 std::execution and I noticed that for cancellation
> >> we still use the `std::stop_token` approach to be able to "cancel" a coroutine by
> >> forcing the user to always call `stop_requested()` before continuing the coroutine, in
> >> addition to needing to pass a `std::stop_source` or `std::stop_token` around, making
> >> it pretty inconvenient to use.
> >>
> >> Now, there are ways to make this more automatic, for example, by embedding the
> >> `std::stop_source` in the coroutine's?promise type and checking at every suspension /
> >> resumption point (`await_suspend()` and `await_resume()` respectfully) whether or not
> >> the coroutine has been cancelled. If so, you can throw an exception and let the
> >> coroutine unwind itself.
> >>
> >> I was wondering if there is a proposal for such an automatic cancellation feature in
> >> the works or already present?
> >>
> >>
> >> I am relatively uneducated in this area; but no, I'm not aware of any plan or proposal to
> >> embed a stop_token into every coroutine.
> >> My kneejerk reaction was "That sounds bad! Every suspend point would become an invisible
> >> interruption point ? you couldn't hold a resource across a suspend point without careful
> >> planning!"
> >> But then I thought again, and realized that we already have /that/. The caller is the one
> >> who decides whether to resume a coroutine_handle<>; if the caller decides to destroy() it
> >> instead, well, that suspend point just turned into an invisible abort anyway, from the
> >> coroutine's?point of view.
> >> Example of safely holding a resource across a suspend: https://godbolt.org/z/azTW57qf8
> >> <https://godbolt.org/z/azTW57qf8>
> >> Example of unsafely (leakily) holding the same: https://godbolt.org/z/f4rTG7Kh3 <https://
> >> godbolt.org/z/f4rTG7Kh3>
> >>
> >> But then I'm afraid I don't understand what feature you're asking for. You can already
> >> "tell a coroutine to unwind itself" by just destroying the handle you were using to talk
> >> to it. Why would you also need a stop_token/stop_source to be involved? Are you trying to
> >> stop someone /else's/ coroutine, like from another thread, without the participation of
> >> its owner? But then what do you expect the coroutine to do ? report .done() despite not
> >> having reached the co_return statement, I guess? Which means what ? call .final_suspend()
> >> on the promise without having first called either `.return_value()` or `.return_void()`?
> >> Is that something that's possible to do today (except manually)? Why would I want that?
> >> In particular, adding the ability for the compiler to generate a new and unusual?sequence
> >> of calls to my promise type means suddenly there's a lot more surface area I'd?need to
> >> cover in my promise types' unit tests to make sure they're not buggy/leaky even in this
> >> new special case.
> >
> >For precedence, python's asyncio has the exception model for cancellation (an exception of
> >type asyncio.CancelledError from a suspension point when a task is cancelled).
> >
> >One thing it allows is to have asynchronous teardown logic, like gracefully terminating
> >network sessions, deregistering from mDNS (zeroconf), etc... .
> >
> >In comparison simply "dropping" the coroutine (destroying the handle) forces the teardown
> >to be either synchronous, or schedule teardown tasks elsewhere, but it's unclear to me
> >where tasks scheduled from the destruction of coroutines can be cleanly joined. From what
> >I heard Rust (or tokio?) has this cancellation model, but I can't comment on that.
> >
> >I know very little about std::execution to comment on that. My gut feeling is that
> >exceptions are too heavy for C++ for a general cancellation solution (but I agree that it
> >is ergonomic, I use it with ASIO), the stop_token is probably sufficiently light, but
> >verbose to use, and just dropping coroutines is missing out on async teardown.
> >
> >I wish herbceptions were pursued, I think herbception cancellation in coroutines would hit
> >the sweet spot.
> >
> >Cheers,
> >L?n?rd
> >
>
>
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>
-- Rhidian De Wit Software Engineer - Barco
Received on 2026-04-14 10:05:40
