Вкратце:
- Когда
spawn()
вызывается, Boost.Asio выполняет некоторые настройки работы, а затем будет использовать strand
к dispatch()
внутренний обработчик, который создает сопрограмму с помощью пользователя, предоставленную функцию в качестве точки входа. При определенных условиях внутренний обработчик может быть вызван при вызове spawn()
, а в других случаях он будет отправлен на io_service
для отложенного вызова.
- coroutine приостанавливается до тех пор, пока операция не завершится, а обработчик завершения не будет вызван,
io_service
будет уничтожен или Boost.Asio обнаруживает, что сопрограмма приостановлена, и нет возможности возобновить ее, после чего Boost.Asio уничтожит сопрограммы.
Как упоминалось выше, когда spawn()
вызывается, Boost.Asio выполняет некоторые настройки работы, а затем будет использовать strand
к dispatch()
внутренний обработчик, который создает сопрограмму с помощью пользователя, предоставленную функцию в качестве точки входа. Когда объект yield_context
передается в качестве обработчика асинхронных операций, Boost.Asio будет вывести сразу после запуска асинхронной операции с обработчиком завершения, который скопирует результаты, и резюме сопроцессор. Ранее упомянутая нить принадлежит сопрограмме, которая используется для обеспечения прибыли встречается до резюме. Давайте рассмотрим простой пример demonstratingspawn()
:
#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.
Что делает акт копирования 'yield_context', как она передается в сопрограммы делать? Если 'foo' передает' yield'' 'bar',' bar' передается 'baz', а' baz' вызывает 'yield' - элемент управления возвращается прямо к' foo'? Когда вызов 'timer.async_wait'« дает », возвращается ли элемент управления обработчику сопроцессора coroutine, который затем возвращается? Когда истечет время позже, как элемент управления возвращается к 'async_wait', который затем возвращается в' my_work'? – CppNoob
@CppNoob Boost.Asio's первоклассная поддержка Boost.Coroutine - довольно тонкий фасад. Вы пытаетесь понять, как Boost.Asio использует Boost.Coroutine, или как работает Boost.Coroutine? Копирование 'yield_context' просто создает другой' yield_context' (а не сопрограмму). Когда 'timer.async_wait()' выдает сопрограмму, управление переходит в левый стек сразу после точки, в которой запускается сопрограмма. Когда вызывается обработчик завершения async_wait, он возобновляет сопрограмму, заставляя выполнение прыгать в правый стек сразу после точки, в которой она была получена. –
Я пытаюсь понять, как Boost Asio использует сопрограммы - не от угла реализации, а как механизм управления потоком. Я думаю, что yield_context является каналом для отказа от контроля над другим контекстом. В этом примере yield_context в my_work ссылается на контекст обработчика сопроцессора-сопроцессора, и он копируется как обработчик завершения для async_wait. Но когда выполняется обработчик завершения async_wait, элемент управления возвращается к my_work, а не обработчику сопроцессора coroutine (который к тому времени вышел). Я, очевидно, не понимаю этого, и надеюсь, что смогу описать, что не ясно. – CppNoob