C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Automatic Coroutine Cancellation

From: Zhao YunShan <dou1984_at_[hidden]>
Date: Sun, 12 Apr 2026 20:34:48 +0800 (CST)
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]p.org
>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
>

Received on 2026-04-12 12:35:00