【问题标题】:Turning a function call which takes a callback into a coroutine将接受回调的函数调用转换为协程
【发布时间】:2021-01-23 23:30:00
【问题描述】:

我正在探索并尝试学习 C++ 协程(在 C++20 中添加)。我正在使用的 SDK 具有异步 API 调用,它们都接受回调,回调是在 SDK 管理的某个后台线程上调用的。


namespace third_party {

bool api_call(const std::string& some_parameter, const std::function<void(std::error_code)>& callback);

} // namespace third_party

我想将此 API 调用包装成可以等待的东西:


namespace my_third_party_sdk_wrapper {

cppcoro::task<std::error_code> api_call(const std::string& some_parameter);
cppcoro::task<std::error_code> api_call(const std::string& some_parameter, cppcoro::cancellation_token token);

} // namespace my_third_party_sdk_wrapper 

我正在考虑使用 cppcoro 库,但这不是必需的,除非包装器的实现变得更加简单。

问题是我不知道如何实现包装器。

【问题讨论】:

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


    【解决方案1】:

    Raymond Chen 有一篇非常好的文章,你可以找到它here

    在你的情况下,你可以这样做。

    namespace my_third_party_async_sdk_wrapper 
    {
    
        auto api_call_async(const std::string& some_parameter)
        {
              struct awaiter : public std::experimental::suspend_always
              {
                   awaiter(const std::string &parameter)
                   :parameter_(parmeter) {}
    
                   bool await_ready() { return false; }
    
                   void await_suspend(std::experimental::coroutine_handle<> handle)
                   { 
                       // use your third party lib call directly here.
                       api_call(parameter_, [handle]() 
                       { 
                           // call the handle to resume the coroutine
                           handle(); 
                       }
                   }
                   const std::string parameter_;
    
              };
              return awaiter(some_parameter);
        }
    
    }
    

    这应该做你想做的。

    【讨论】:

    • 谢谢!只是一个快速的问题,原来的回调有一个参数,我会把它放在哪里?是否进入coroutine_handle&lt;&gt; 类型?
    • 我做了一些修改,我犯了两个错误。 1)await_ready需要返回false,告诉机器立即调用await_suspend。您将参数存储在 awaiter 中,然后当它挂起时,它会使用成员参数调用 api_call。然后当你的 api_call 调用它的回调时,你调用 handle() 来恢复。这并不能真正处理输出参数或返回值。您可以通过将引用传递给等待者并分配它来完成。 但是,您需要注意引用的寿命足够长。
    【解决方案2】:

    cppreference.com 上的一个简单(运行)示例,“switch_to_new_thread”:https://en.cppreference.com/w/cpp/language/coroutines

    打开有两个问题:

    • 将参数传递给回调
    • 将回调链接到调用堆栈

    这段代码显示了一个解决方案https://wandbox.org/permlink/OGjmtFWsgjnn3GxX

    在此处查找最新版本:https://github.com/andreaspfaffenbichler/Continuation/blob/master/Continuation.cpp

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-15
      • 1970-01-01
      • 2015-10-12
      • 1970-01-01
      相关资源
      最近更新 更多