【问题标题】:What is the best way to return value from promise_type从 promise_type 返回值的最佳方法是什么
【发布时间】:2021-12-30 13:44:23
【问题描述】:

我对 C++20 中的协程有点坚持。我尝试创建一个异步任务:


template <typename T>
struct Task {
 public:
  struct promise_type {
    using Handle = std::coroutine_handle<promise_type>;

    promise_type() = default;
    ~promise_type() = default;

    Task get_return_object() { return Task{Handle::from_promise(*this)}; }

    std::suspend_never initial_suspend() { return {}; }
    std::suspend_never final_suspend() noexcept { return {}; }

    void return_value(T val) noexcept { value_ = val; }
    void unhandled_exception() { std::cout << "Unhandled exception in coroutine\n"; }
    
    T value_;
  };

  explicit Task(typename promise_type::Handle coro) : coro_(coro) {}

  std::optional<T> Get() { 
    return coro_.done() ? 
      std::make_optional(coro_.promise().value_) : std::nullopt; 
  }

 private:
  typename promise_type::Handle coro_;
};

虚拟用法示例:

Task<int> Coro() {
  co_await std::suspend_never();
  co_return 1;
}

int main() {
  auto task = Coro();
  std::cout << *task.Get();
  return 0;
}

问题出在Task::Get() 方法中。当我试图从promise_type 获取值时,它已经被破坏了。我正在尝试用指针连接 Task 和 promise_type,但它看起来有点难看。我相信对此有一些标准且简单的方法。

更新:

只有当协程没有挂起时才会发生这种情况。在这种情况下,promise_type 在 Get() 调用之前被销毁。

【问题讨论】:

    标签: c++ c++20 coroutine


    【解决方案1】:

    我自己只是在学习协程,但我相信解决这个问题的方法是改变 Task 的销毁方式。

    目前,您有final_suspend 返回std::suspend_never。因此控制权立即返回给调用者 (main),promise 被销毁。在这种情况下,您必须执行以下操作:

    我正在尝试用指针连接Task和promise_type,但是看起来有点难看

    基本上是为了让promise 可以将其return_value 写入Task


    但我们可以做一些不同的事情。您可以始终暂停:

    std::suspend_always final_suspend() noexcept { return {}; }
    

    并确保Task 本身销毁协程:

    ~Task() {
        if (coro_) coro_.destroy();
    }
    

    这样,promisetask 被销毁之前不会被销毁,这意味着task.Get() 没有访问一个悬空的......协程。你可以看到区别here

    【讨论】:

      猜你喜欢
      • 2010-09-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-15
      相关资源
      最近更新 更多