boost::asio::什么产卵呢?

时间:2021-11-21 00:34:04

I am unable to form a mental picture of how the control flow happens with spawn.

我无法想象控制流是如何在产卵时发生的。

  1. When I call spawn(io_service, my_coroutine), does it add a new handler to the io_service queue that wraps a call to the my_coroutine?

    当我调用spawn(io_service, my_coroutine)时,它会向io_service队列添加一个新的处理程序来包装对my_coroutine的调用吗?

  2. When inside the coroutine I call an async function passing it my yield_context, does it suspend the coroutine until the async operation completes?

    当我在coroutine中调用一个异步函数并将其传递给我的yield_context时,它是否在异步操作完成之前暂停该coroutine ?

    void my_coroutine(yield_context yield)
    {
      ...
      async_foo(params ..., yield);
      ...   // control comes here only once the async_foo operation completes
    }

What I don't understand is how we avoid waits. Say if my_coroutine serves a TCP connection, how are other instances of my_coroutine invoked while on particular instance is suspended, waiting for async_foo to complete?

我不明白的是我们如何避免等待。例如,如果my_coroutine服务于TCP连接,当在特定实例上挂起等待async_foo完成时,如何调用my_coroutine的其他实例?

1 个解决方案

#1


19  

In short:

简而言之:

  1. When spawn() is invoked, Boost.Asio performs some setup work and then will use a strand to dispatch() an internal handler that creates a coroutine using the user provided function as an entry point. Under certain conditions, the internal handler can be will be invoked within the call to spawn(), and other times it will be posted to the io_service for deferred invocation.
  2. 调用spawn()时,使用Boost。Asio执行一些设置工作,然后使用一个链来分派()一个内部处理程序,它使用用户提供的函数作为入口点创建一个coroutine。在某些条件下,可以在调用中调用内部处理程序来spawn(),而在其他时候,它将被发送到io_service以进行延迟调用。
  3. The coroutine is suspended until either the operation completes and the completion handler is invoked, the io_service is destroyed, or Boost.Asio detects that the coroutine has been suspended with no way to resume it, at which point Boost.Asio will destroy the coroutine.
  4. coroutine将被挂起,直到操作完成并调用完成处理程序、销毁io_service或Boost为止。Asio检测到警戒线已被暂停,无法恢复,此时Boost。阿西奥会摧毁警戒线。

As mentioned above, when spawn() is invoked, Boost.Asio performs some setup work and then will use a strand to dispatch() an internal handler that creates a coroutine using the user provided function as an entry point. When the yield_context object is passed as a handler to asynchronous operations, Boost.Asio will yield immediately after initiating the asynchronous operation with a completion handler that will copy results and resume the coroutine. The previously mentioned strand is owned by the coroutine is used to guarantee the yield occurs before resume. Lets consider a simple example demonstrating spawn():

如上所述,在调用spawn()时,使用Boost。Asio执行一些设置工作,然后使用一个链来分派()一个内部处理程序,它使用用户提供的函数作为入口点创建一个coroutine。当producd_context对象作为处理程序传递给异步操作时,Boost。Asio将在初始化异步操作后立即产生一个完成处理程序,该处理程序将复制结果并恢复coroutine。前文所述的链为coroutine所有,用于保证产量在恢复前发生。让我们考虑一个演示spawn()的简单示例:

#include <iostream>
#include <boost/asio.hpp>
#include <boost/asio/spawn.hpp>

boost::asio::io_service io_service;

void other_work()
{
  std::cout << "Other work" << std::endl;
}

void my_work(boost::asio::yield_context yield_context)
{
  // Add more work to the io_service.
  io_service.post(&other_work);

  // Wait on a timer within the coroutine.
  boost::asio::deadline_timer timer(io_service);
  timer.expires_from_now(boost::posix_time::seconds(1));
  std::cout << "Start wait" << std::endl;
  timer.async_wait(yield_context);
  std::cout << "Woke up" << std::endl;    
}

int main ()
{
  boost::asio::spawn(io_service, &my_work);
  io_service.run();
}

The above example outputs:

上面的示例输出:

Start wait
Other work
Woke up

Here is an attempt to illustrate the execution of the example. Paths in | indicate the active stack, : indicates the suspended stack, and arrows are used to indicate transfer of control:

这里尝试说明示例的执行情况。|中的路径表示活动堆栈:表示挂起堆栈,箭头表示控制转移:

boost::asio::io_service io_service;
boost::asio::spawn(io_service, &my_work);
`-- dispatch a coroutine creator
    into the io_service.
io_service.run();
|-- invoke the coroutine creator
|   handler.
|   |-- create and jump into
|   |   into coroutine         ----> my_work()
:   :                                |-- post &other_work onto
:   :                                |   the io_service
:   :                                |-- create timer
:   :                                |-- set timer expiration
:   :                                |-- cout << "Start wait" << endl;
:   :                                |-- timer.async_wait(yield)
:   :                                |   |-- create error_code on stack
:   :                                |   |-- initiate async_wait operation,
:   :                                |   |   passing in completion handler that
:   :                                |   |   will resume the coroutine
|   `-- return                 <---- |   |-- yield
|-- io_service has work (the         :   :
|   &other_work and async_wait)      :   :
|-- invoke other_work()              :   :
|   `-- cout << "Other work"         :   :
|       << endl;                     :   :
|-- io_service still has work        :   :
|   (the async_wait operation)       :   :
|   ...async wait completes...       :   :
|-- invoke completion handler        :   :
|   |-- copies error_code            :   :
|   |   provided by service          :   :
|   |   into the one on the          :   :
|   |   coroutine stack              :   :
|   |-- resume                 ----> |   `-- return error code
:   :                                |-- cout << "Woke up." << endl;
:   :                                |-- exiting my_work block, timer is 
:   :                                |   destroyed.
|   `-- return                 <---- `-- coroutine done, yielding
`-- no outstanding work in 
    io_service, return.

#1


19  

In short:

简而言之:

  1. When spawn() is invoked, Boost.Asio performs some setup work and then will use a strand to dispatch() an internal handler that creates a coroutine using the user provided function as an entry point. Under certain conditions, the internal handler can be will be invoked within the call to spawn(), and other times it will be posted to the io_service for deferred invocation.
  2. 调用spawn()时,使用Boost。Asio执行一些设置工作,然后使用一个链来分派()一个内部处理程序,它使用用户提供的函数作为入口点创建一个coroutine。在某些条件下,可以在调用中调用内部处理程序来spawn(),而在其他时候,它将被发送到io_service以进行延迟调用。
  3. The coroutine is suspended until either the operation completes and the completion handler is invoked, the io_service is destroyed, or Boost.Asio detects that the coroutine has been suspended with no way to resume it, at which point Boost.Asio will destroy the coroutine.
  4. coroutine将被挂起,直到操作完成并调用完成处理程序、销毁io_service或Boost为止。Asio检测到警戒线已被暂停,无法恢复,此时Boost。阿西奥会摧毁警戒线。

As mentioned above, when spawn() is invoked, Boost.Asio performs some setup work and then will use a strand to dispatch() an internal handler that creates a coroutine using the user provided function as an entry point. When the yield_context object is passed as a handler to asynchronous operations, Boost.Asio will yield immediately after initiating the asynchronous operation with a completion handler that will copy results and resume the coroutine. The previously mentioned strand is owned by the coroutine is used to guarantee the yield occurs before resume. Lets consider a simple example demonstrating spawn():

如上所述,在调用spawn()时,使用Boost。Asio执行一些设置工作,然后使用一个链来分派()一个内部处理程序,它使用用户提供的函数作为入口点创建一个coroutine。当producd_context对象作为处理程序传递给异步操作时,Boost。Asio将在初始化异步操作后立即产生一个完成处理程序,该处理程序将复制结果并恢复coroutine。前文所述的链为coroutine所有,用于保证产量在恢复前发生。让我们考虑一个演示spawn()的简单示例:

#include <iostream>
#include <boost/asio.hpp>
#include <boost/asio/spawn.hpp>

boost::asio::io_service io_service;

void other_work()
{
  std::cout << "Other work" << std::endl;
}

void my_work(boost::asio::yield_context yield_context)
{
  // Add more work to the io_service.
  io_service.post(&other_work);

  // Wait on a timer within the coroutine.
  boost::asio::deadline_timer timer(io_service);
  timer.expires_from_now(boost::posix_time::seconds(1));
  std::cout << "Start wait" << std::endl;
  timer.async_wait(yield_context);
  std::cout << "Woke up" << std::endl;    
}

int main ()
{
  boost::asio::spawn(io_service, &my_work);
  io_service.run();
}

The above example outputs:

上面的示例输出:

Start wait
Other work
Woke up

Here is an attempt to illustrate the execution of the example. Paths in | indicate the active stack, : indicates the suspended stack, and arrows are used to indicate transfer of control:

这里尝试说明示例的执行情况。|中的路径表示活动堆栈:表示挂起堆栈,箭头表示控制转移:

boost::asio::io_service io_service;
boost::asio::spawn(io_service, &my_work);
`-- dispatch a coroutine creator
    into the io_service.
io_service.run();
|-- invoke the coroutine creator
|   handler.
|   |-- create and jump into
|   |   into coroutine         ----> my_work()
:   :                                |-- post &other_work onto
:   :                                |   the io_service
:   :                                |-- create timer
:   :                                |-- set timer expiration
:   :                                |-- cout << "Start wait" << endl;
:   :                                |-- timer.async_wait(yield)
:   :                                |   |-- create error_code on stack
:   :                                |   |-- initiate async_wait operation,
:   :                                |   |   passing in completion handler that
:   :                                |   |   will resume the coroutine
|   `-- return                 <---- |   |-- yield
|-- io_service has work (the         :   :
|   &other_work and async_wait)      :   :
|-- invoke other_work()              :   :
|   `-- cout << "Other work"         :   :
|       << endl;                     :   :
|-- io_service still has work        :   :
|   (the async_wait operation)       :   :
|   ...async wait completes...       :   :
|-- invoke completion handler        :   :
|   |-- copies error_code            :   :
|   |   provided by service          :   :
|   |   into the one on the          :   :
|   |   coroutine stack              :   :
|   |-- resume                 ----> |   `-- return error code
:   :                                |-- cout << "Woke up." << endl;
:   :                                |-- exiting my_work block, timer is 
:   :                                |   destroyed.
|   `-- return                 <---- `-- coroutine done, yielding
`-- no outstanding work in 
    io_service, return.