【问题标题】:C++20 Coroutines, await_resume return lvalue, Segmentation faultC++20 协程,await_resume 返回左值,分段错误
【发布时间】:2021-07-08 17:30:51
【问题描述】:

正在发生

我想将仅移动数据存储到promise_type,并在协程中获取。我尝试从await_resume() 返回返回左值。结果是编译成功但是执行过程中出现Segmentation fault

我该如何改进?


环境

  • 操作系统:WSL2 Ubuntu 20.04
  • 编译器:gcc 10.3
  • 命令:g++ -std=c++20 -fcoroutines main.cpp

代码

main.cpp:

#include <iostream>
#include <coroutine>
#include <memory>

struct task
{
    struct promise_type
    {
        using data_type = std::unique_ptr<int>;

        task get_return_object() noexcept
        {
            return task(std::coroutine_handle<promise_type>::from_promise(*this));
        }
        std::suspend_never initial_suspend() const noexcept { return {}; }
        void unhandled_exception() {}
        std::suspend_always final_suspend() const noexcept { return {}; }

        data_type data; // my data
    };

    void set_data(promise_type::data_type&& data) // [2] set my data
    {
        handle.promise().data = std::forward<promise_type::data_type>(data);
    }

    void resume()
    {
        handle.resume();
    }

    task(std::coroutine_handle<promise_type> handle) : handle(handle) {}

private:
    std::coroutine_handle<promise_type> handle;
};

struct awaitalbe
{
    bool await_ready() { return true; }
    void await_suspend(std::coroutine_handle<task::promise_type> handle) { this->handle = handle; }
    task::promise_type::data_type&& await_resume()
    {
        return std::move(handle.promise().data); // [3] get my data
    }

    std::coroutine_handle<task::promise_type> handle;
};

task f()
{
    auto p2 = co_await awaitalbe{}; // [4] Segmentation fault here. after [3]
    std::cout << (*p2) << std::endl;
}

int main(int argc, char* argv[])
{
    auto task1 = f();

    task::promise_type::data_type p1 = std::make_unique<task::promise_type::data_type::element_type>(10);
    task1.set_data(std::move(p1)); // [1] set my data

    task1.resume();
    return 0;
}

【问题讨论】:

    标签: c++ c++20 c++-coroutine


    【解决方案1】:

    在您的struct awaitable 中,您有:

    bool await_ready() { return true; }
    

    澄清一下,await_ready 是一种用于确定对应于可等待对象的结果是否就绪的机制。如果它准备好了,那么真的没有充分的理由暂停调用协程(即 co_awaits 等待结果的协程)并等待结果 - 只需调用检索结果的 await_resume

    它允许您执行以下操作:

    bool await_ready() {
      if (will_read_block()) {
         return false;
      }
      read_some_data_from_file();
      return true;
    }
    

    这样非阻塞读取将同步完成。

    在你的情况下,你总是返回 true。这告诉运行时:当协程等待awaitable 时,永远不要挂起该协程并直接调用await_resume,完全跳过挂起和await_suspend。事实上,如果你在await_suspend 中的await_suspend 中设置断点(或者如果你的调试器不喜欢协程,则使用打印语句),你会发现它永远不会被调用。因此,您从未真正为 awaitable 结构中的 handle 成员分配任何内容,当您尝试从中获得承诺时会导致未定义的行为。

    解决方案:只需从await_ready 返回false

    【讨论】:

      猜你喜欢
      • 2021-01-28
      • 1970-01-01
      • 2015-02-10
      • 2021-01-13
      • 2015-03-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多