Я запускаю несколько сопрограмм с asio :: spawn, и я хочу подождать, пока все это не закончится, и затем выполнить какую-то другую работу. Как это можно сделать?
Поток управления следующий:
asio::spawn (io, [] (asio::yield_context yield) {
...
// starting few coroutines
asio::spawn (yield, [] (asio::yield_context yield2) { ... });
asio::spawn (yield, [] (asio::yield_context yield2) { ... });
asio::spawn (yield, [] (asio::yield_context yield2) { ... });
asio::spawn (yield, [] (asio::yield_context yield2) { ... });
// now I want to wait for all of them to finish before I do
// some other work?
...
});
io.run ();
ОБНОВИТЬ
Ниже приведен пример кода
#include <boost/asio.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/asio/steady_timer.hpp>
#include <chrono>
#include <iostream>
using namespace std;
int main ()
{
using namespace boost::asio;
io_service io;
spawn (io, [&] (yield_context yield) {
cout << "main coro starts\n";
auto lambda = [&] (yield_context yield)
{
cout << "in lambda inside subcoroutine - starts\n";
steady_timer t (io, std::chrono::seconds (1));
t.async_wait (yield);
cout << "in lambda inside subcoroutine - finishes\n";
};
// starting few coroutines
spawn (yield, lambda);
spawn (yield, lambda);
// now I want to wait for all of them to finish before I do
// some other work?
// ???
cout << "main coro finishes\n";
});
io.run ();
}
И вывод:
// main coro starts
// in lambda inside subcoroutine - starts
// in lambda inside subcoroutine - starts
// main coro finishes <----
// in lambda inside subcoroutine - finishes
// in lambda inside subcoroutine - finishes
Пока я ожидаю
// main coro starts
// in lambda inside subcoroutine - starts
// in lambda inside subcoroutine - starts
// in lambda inside subcoroutine - finishes
// in lambda inside subcoroutine - finishes
// main coro finishes
(см. место линии «главная отделка»)
Лучшим вариантом будет использование волокон (boost.fiber интегрируется в boost.asio).
boost :: fiber является сопрограммой + планировщик + классы синхронизации (API, например, std :: thread) и может использоваться в контексте boost.asio, как сопрограммы.
Я нашел … своего рода обходной путь.
Я могу использовать таймер с бесконечной продолжительностью и отменить его из последней подпрограммы. Это разбудит главную сопрограмму.
#include <boost/asio.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/asio/steady_timer.hpp>
#include <iostream>
using namespace std;
int main ()
{
using namespace boost::asio;
io_service io;
spawn (io, [&] (yield_context yield) {
cout << "main coro starts\n";steady_timer rendez_vous (io, steady_timer::clock_type::duration::max ());
/* volatile */ int counter = 2;auto lambda = [&] (yield_context yield)
{
cout << "in lambda inside subcoroutine - starts\n";
steady_timer t (io, boost::chrono::seconds (1));
t.async_wait (yield);
cout << "in lambda inside subcoroutine - finishes\n";
if (--counter == 0)
rendez_vous.cancel ();
};
// starting few coroutines
spawn (yield, lambda);
spawn (yield, lambda);
// now I want to wait for all of them to finish before I do
// some other work?
// ???
boost::system::error_code ignored_ec;
rendez_vous.async_wait (yield [ignored_ec]);
// ignore errors here by reason.
cout << "main coro finishes\n";
});
io.run ();
}
Честно говоря, мне не нравится это решение, потому что оно злоупотребляет концепцией и объектом «таймера» и является возможной тратой системных ресурсов.