如何恢复stackful协程的在其链的上下文中执行? [英] How resume the execution of a stackful coroutine in the context of its strand?

查看:183
本文介绍了如何恢复stackful协程的在其链的上下文中执行?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

using Yield = asio::yield_context;
using boost::system::error_code;
int Func(Yield yield) {
  error_code ec;
  asio::detail::async_result_init<Yield, void(error_code, int)> init(yield[ec]);
  std::thread th(std::bind(Process, init.handler));
  int result = init.result.get();  // <--- yield at here
  return result;
}

如何实施过程函数功能将在函数功能最初催生了?

推荐答案

Boost.Asio的使用一个辅助函数,的 asio_handler_invoke ,提供调用战略的定制点。例如,当一个处理器被包裹由,调用策略将导致处理程序要通过派出时调用。正如文档指出, asio_handler_invoke 应通过参数相关的查找调用。

Boost.Asio uses a helper function, asio_handler_invoke, to provide a customization point for invocation strategies. For example, when a Handler has been wrapped by a strand, the invocation strategy will cause the handler to be dispatched through the strand upon invocation. As noted in the documentation, asio_handler_invoke should be invoked via argument-dependent lookup.

using boost::asio::asio_handler_invoke;
asio_handler_invoke(nullary_functor, &handler);


有关stackful协同程序,也有产生的协同程序时要考虑到各种重要细节和调用的 handler_type 用的 yield_context 恢复协程:


For stackful coroutines, there are various important details to take into consideration when yielding the coroutine and when invoking the handler_type associated with a yield_context to resume the coroutine:


  • 如果code目前在协程运行,那么它是在与协程相关的。从本质上讲,一个简单的处理程序是由的恢复协程,导致执行跳转到协程,在当前阻止处理程序的链<包裹/ code>。当协程良率,执行跳回处理程序,使其能够完成。

  • 重生() 增加了工作到 io_service对象(处理程序将启动,并跳转到协程),协程本身就是不行。以prevent的 io_service对象事件从结束而协程是优秀的循环,可能需要增加工作在 io_service对象屈服前。

  • Stackful协同程序使用帮助的恢复的调用之前保证协同程序的收益的。 ASIO 1.10.6 /升压1.58启用能够从初始函数中调用安全地完成处理程序。在此之前的版本要求在完成处理程序没有从启动功能中调用,因为它的调用战略将<一个href=\"http://www.boost.org/doc/libs/1_59_0/doc/html/boost_asio/reference/io_service__strand/dispatch.html\"相对=nofollow> 调度() ,导致协同程序被暂停之前,尝试恢复。

  • If code is currently running in the coroutine, then it is within the strand associated with the coroutine. Essentially, a simple handler is wrapped by the strand that resumes the coroutine, causing execution to jump to the coroutine, blocking the handler currently in the strand. When the coroutine yields, execution jumps back to the strand handler, allowing it to complete.
  • While spawn() adds work to the io_service (a handler that will start and jump to the coroutine), the coroutine itself is not work. To prevent the io_service event loop from ending while a coroutine is outstanding, it may be necessary to add work to the io_service before yielding.
  • Stackful coroutines use a strand to help guarantee the coroutine yields before resume is invoked. Asio 1.10.6 / Boost 1.58 enabled being able to safely invoke the completion handler from within the initiating function. Prior versions required that the completion handler was not invoked from within the initiating function, as its invocation strategy would dispatch(), causing the coroutine to attempt resumption before being suspended.

下面是一个完整的例如:

#include <iostream>    // std::cout, std::endl
#include <chrono>      // std::chrono::seconds
#include <functional>  // std::bind
#include <thread>      // std::thread
#include <utility>     // std::forward
#include <boost/asio.hpp>
#include <boost/asio/spawn.hpp>

template <typename CompletionToken, typename Signature>
using handler_type_t = typename boost::asio::handler_type<
  CompletionToken, Signature>::type;

template <typename Handler>
using async_result = boost::asio::async_result<Handler>;

/// @brief Helper type used to initialize the asnyc_result with the handler.
template <typename CompletionToken, typename Signature>
struct async_completion
{
  typedef handler_type_t<CompletionToken, Signature> handler_type;

  async_completion(CompletionToken&& token)
    : handler(std::forward<CompletionToken>(token)),
      result(handler)
  {}

  handler_type handler;
  async_result<handler_type> result;
};

template <typename Signature, typename CompletionToken>
typename async_result<
  handler_type_t<CompletionToken, Signature>
>::type
async_func(CompletionToken&& token, boost::asio::io_service& io_service)
{
  // The coroutine itself is not work, so guarantee the io_service has
  // work.
  boost::asio::io_service::work work(io_service);

  // Initialize the async completion handler and result.
  async_completion<CompletionToken, Signature> completion(
      std::forward<CompletionToken>(token));

  auto handler = completion.handler;
  std::cout << "Spawning thread" << std::endl;
  std::thread([](decltype(handler) handler)
    {
      // The handler will be dispatched to the coroutine's strand.
      // As this thread is not running within the strand, the handler
      // will actually be posted, guaranteeing that yield will occur
      // before the resume.
      std::cout << "Resume coroutine" << std::endl;
      using boost::asio::asio_handler_invoke;
      asio_handler_invoke(std::bind(handler, 42), &handler);
    }, handler).detach();

  // Demonstrate that the handler is serialized through the strand by
  // allowing the thread to run before suspending this coroutine.
  std::this_thread::sleep_for(std::chrono::seconds(2));

  // Yield the coroutine.  When this yields, execution transfers back to
  // a handler that is currently in the strand.  The handler will complete
  // allowing other handlers that have been posted to the strand to run.
  std::cout << "Suspend coroutine" << std::endl;
  return completion.result.get();
}

int main()
{
  boost::asio::io_service io_service;

  boost::asio::spawn(io_service,
    [&io_service](boost::asio::yield_context yield)
    {
      auto result = async_func<void(int)>(yield, io_service);
      std::cout << "Got: " << result << std::endl;
    });

  std::cout << "Running" << std::endl;
  io_service.run();
  std::cout << "Finish" << std::endl;
}

输出:

Running
Spawning thread
Resume coroutine
Suspend coroutine
Got: 42
Finish


有关更多信息,请阅读考虑图书馆基金会
异步操作
的。它提供了更多的细节到异步操作的成分,如何签名影响 async_result 和<$的整体设计C $ C> async_result
handler_type async_completion


For much more details, please consider reading Library Foundations for Asynchronous Operations. It provides much greater detail into the composition of asynchronous operations, how Signature affects async_result, and the overall design of async_result, handler_type, and async_completion.

这篇关于如何恢复stackful协程的在其链的上下文中执行?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆