Что делает boost :: asio :: spawn?

Я не могу сформировать мысленную картину того, как поток управления происходит с порождением.

  1. Когда я звоню spawn(io_service, my_coroutine)это добавляет новый обработчик к io_service очередь, которая оборачивает вызов my_coroutine?

  2. Когда внутри сопрограммы я вызываю асинхронную функцию, передавая ее мой yield_context, приостанавливает ли сопрограмму, пока не завершится асинхронная операция?

    void my_coroutine (yield_context yield)
    {
    ...
    async_foo (params ..., yield);
    ... // управление приходит сюда только после завершения операции async_foo
    }

Чего я не понимаю, так это как мы избегаем ожидания. Скажи если my_coroutine обслуживает соединение TCP, как другие экземпляры my_coroutine вызывается в то время как на конкретном экземпляре приостановлено, ожидая async_foo завершить?

7

Решение

Короче:

  1. когда spawn() Boost.Asio выполняет некоторые настройки и затем использует strand в dispatch() внутренний обработчик, который создает сопрограмму, используя предоставленную пользователем функцию в качестве точки входа. При определенных условиях внутренний обработчик может быть вызван в вызове spawn()и в других случаях он будет опубликован на io_service для отложенного вызова.
  2. Сопрограмма приостанавливается до тех пор, пока либо операция не завершится, и не будет вызван обработчик завершения, io_service уничтожен или Boost.Asio обнаруживает, что сопрограмма была приостановлена ​​без возможности возобновления, после чего Boost.Asio уничтожит сопрограмму.

Как упоминалось выше, когда spawn() Boost.Asio выполняет некоторые настройки и затем использует strand в dispatch() внутренний обработчик, который создает сопрограмму, используя предоставленную пользователем функцию в качестве точки входа. Когда yield_context объект передается в качестве обработчика асинхронных операций, Boost.Asio Уступать сразу после запуска асинхронной операции с обработчиком завершения, который будет копировать результаты и продолжить сопрограмма. Ранее упомянутая цепь принадлежит сопрограмме и используется для гарантии Уступать происходит раньше продолжить. Давайте рассмотрим простой пример демонстрирующий 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();
}

Приведенный выше пример выводит:

Start wait
Other work
Woke up

Вот попытка проиллюстрировать выполнение примера. Пути в | указать активный стек, : указывает на приостановленный стек, а стрелки используются для обозначения передачи управления:

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.
20

Другие решения


По вопросам рекламы [email protected]