【问题标题】:C++: How to properly use generator<>, task<>, and lazy<> classes available in #include<coroutine>?C++:如何正确使用#include<coroutine> 中可用的生成器<>、任务<> 和惰性<> 类?
【发布时间】:2020-10-26 17:54:22
【问题描述】:

我收集(来自here)协程类型大致分为3种:

生成器、任务和惰性

我的问题是:如果我想决定返回类型,这三者之间有什么区别?

例如:延迟加载一组文件处理程序的协同程序的返回类是什么?我的实现将使用task&lt;FileHandler&gt;generator&lt;Filehandler&gt; 来实现相同的效果。

我查看了“执行”部分下的this,了解promise object 与协程交互时的限制。但我只能找到实现差异而不是方法差异。

【问题讨论】:

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


    【解决方案1】:

    我做了一些研究,我相信答案如下:

    首先,C++ 中没有lazy&lt;&gt; 类。 https://en.cppreference.com/w/cpp/language/coroutines 错了。 (参考草稿确认)

    所以,generator&lt;T&gt;task&lt;T&gt; 的返回类型是有区别的。

    TLDR;

    最容易记住的方法是:

    generatorsco_yield 相关联;而tasksco_await 相关联

    生成器

    与生成器类关联的 co_yield 机制与我们在 python 中遇到的完全相同(请参阅文档),也与操作系统机制中的thread_suspend 概念非常相似。

    您可以选择同步或异步实现它。 (有关示例,请参阅cppcoro library。)

    生成器类型(种类)如下所示:

    struct generator {
      struct promise_type;
      using handle = std::coroutine_handle<promise_type>;
      struct promise_type {
        int current_value;
        static auto get_return_object_on_allocation_failure() { return generator{nullptr}; }
        auto get_return_object() { return generator{handle::from_promise(*this)}; }
        auto initial_suspend() { return std::suspend_always{}; }
        auto final_suspend() noexcept { return std::suspend_always{}; }
        void unhandled_exception() { std::terminate(); }
        void return_void() {}
        auto yield_value(int value) {
          current_value = value;
          return std::suspend_always{};
        }
      };
      bool move_next() { return coro ? (coro.resume(), !coro.done()) : false; }
      int current_value() { return coro.promise().current_value; }
      generator(generator const&) = delete;
      generator(generator && rhs) : coro(rhs.coro) { rhs.coro = nullptr; }
      ~generator() { if (coro) coro.destroy(); }
    private:
      generator(handle h) : coro(h) {}
      handle coro;
    };
    

    您将使用如下生成器类型:

    generator f() { co_yield 1; co_yield 2; }
    

    任务

    另一方面,任务与co_await 表达式相关联。它需要Awaitable&lt;T&gt;Awaiter&lt;T&gt; 概念,因此请确保正确使用与这两个概念相关的约束。 Awaiter 概念包括以下约束:await_readyawait_suspendawait_resume。 Awaitable 概念有以下约束:(1) co_await 特化/重载和 (2) await_transform 没有重载。[ ref ]

    任务类型如下所示:

    class task
      {
      public:
    
        using promise_type = <unspecified>;
        using value_type = T;
    
        task() noexcept;
    
        task(task&& other) noexcept;
        task& operator=(task&& other);
    
        task(const task& other) = delete;
        task& operator=(const task& other) = delete;
    
        bool is_ready() const noexcept;
    
        Awaiter<T&> operator co_await() const & noexcept;
        Awaiter<T&&> operator co_await() const && noexcept;
    
    
        Awaitable<void> when_ready() const noexcept;
      };
    

    您可以选择使用这些概念(最好是我的方法),或者如果您还不熟悉这些概念的存在,那么您可能需要自己实现相关的约束来实现。

    使用任务就像[ref]

    task<> tcp_echo_server() {
      char data[1024];
      for (;;) {
        size_t n = co_await socket.async_read_some(buffer(data));
        co_await async_write(socket, buffer(data, n));
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-02-08
      • 2020-08-07
      • 2019-12-13
      • 2015-01-25
      • 1970-01-01
      • 1970-01-01
      • 2013-01-16
      • 1970-01-01
      相关资源
      最近更新 更多