使用final_suspend进行延续的C ++ 20协程

问题描述 投票:2回答:1

背景

[确信C++ stackless coroutines are pretty awesome。我一直在为代码库实现协程,并在final_suspend中发现了一个奇怪的地方。

上下文

假设您具有以下final_suspend函数:

final_awaitable final_suspend() noexcept
{
    return {};
}

而且,final_awaitable的实现如下:

struct final_awaitable
{
    bool await_ready() const noexcept
    {
        return false;
    }
    default_handle_t await_suspend( promise_handle_t h ) const noexcept
    { 
        return h.promise().continuation();
    }
    void await_resume() const noexcept {}
};

如果从任务队列中自动检索到此处的延续,则任务队列可能为空(可能在await_readyawait_suspend之间的任何时间发生),那么await_suspend必须能够返回一个空白的延续。

据我了解,当await_suspend返回一个句柄时,返回的句柄将立即恢复(N4775草案中的5.1)。因此,如果此处没有可用的继续,则任何应用程序都将崩溃,因为从await_suspend接收到恢复后,将在无效的协程句柄上调用简历。

以下是执行顺序:

final_suspend                        Constructs final_awaitable.
    final_awaitable::await_ready     Returns false, triggering await_suspend.
    final_awaitable::await_suspend   Returns a continuation (or empty continuation).
        continuation::resume         This could be null if a retrieved from an empty work queue.

似乎没有为有效的句柄指定检查(就像await_suspend返回bool一样。

问题

  1. 在这种情况下,您如何将工作队列添加到await_suspend而不加锁?编辑:和不可伸缩的堆栈方法。
  2. 为什么底层协程实现不检查有效句​​柄。

导致崩溃的人为的示例是here

解决方案

  1. 使用虚拟任务,它是co_yield的无限循环。这是一种浪费的周期,我宁愿不必这样做,也需要为每个执行线程为虚拟任务创建单独的句柄,这似乎很愚蠢。

  2. 创建std::coroutine_handle的特殊化,其中简历不执行任何操作,返回该句柄的实例。我宁愿不专门研究标准库。这也不起作用,因为coroutine_handle <>没有虚拟的done()resume()

c++ c++20 continuations c++-coroutine
1个回答
1
投票

关于:(实际上只是一个很大的评论。)

struct final_awaitable
{
    bool await_ready() const noexcept
    {
        return false;
    }
    bool await_suspend( promise_handle_t h ) const noexcept
    { 
        auto continuation = h.promise().atomically_pop_a_continuation();
        if (continuation)
           continuation.handle().resume();
        return true;//or whatever is meaningfull for your case.
    }
    void await_resume() const noexcept {}
};
© www.soinside.com 2019 - 2024. All rights reserved.