Date: Tue, 14 Apr 2026 20:19:44 +0800 (CST)
Cancellation can be decomposed into wait_for_any(io_coroutine(), cancel_coroutine()) and manual resumption.
For protocols like HTTP/2 or MySQL, the cancellation process requires sending a cancel message first, then manually resuming the waiting I/O coroutine to either continue execution or exit.
However, for native TCP protocols, a direct cancellation might result in data incompleteness or corruption.
This implies that cancellation must be handled at the protocol layer, which is something the C++ standard itself cannot achieve.
At 2026-04-14 18:05:26, "Rhidian De Wit" <rhidiandewit_at_[hidden]> wrote:
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:
A co_event that supports manual suspension and resumption, giving you full control!!!
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
>
For protocols like HTTP/2 or MySQL, the cancellation process requires sending a cancel message first, then manually resuming the waiting I/O coroutine to either continue execution or exit.
However, for native TCP protocols, a direct cancellation might result in data incompleteness or corruption.
This implies that cancellation must be handled at the protocol layer, which is something the C++ standard itself cannot achieve.
At 2026-04-14 18:05:26, "Rhidian De Wit" <rhidiandewit_at_[hidden]> wrote:
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:
A co_event that supports manual suspension and resumption, giving you full control!!!
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]g https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals -- Rhidian De Wit Software Engineer - Barco
Received on 2026-04-14 12:19:53
