Как ждать завершения всего форсирования: стопки сопрограмм asio?

Я запускаю несколько сопрограмм с 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

(см. место линии «главная отделка»)

7

Решение

Лучшим вариантом будет использование волокон (boost.fiber интегрируется в boost.asio).
boost :: fiber является сопрограммой + планировщик + классы синхронизации (API, например, std :: thread) и может использоваться в контексте boost.asio, как сопрограммы.

1

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

Я нашел … своего рода обходной путь.

Я могу использовать таймер с бесконечной продолжительностью и отменить его из последней подпрограммы. Это разбудит главную сопрограмму.

Пример Coliru

#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 ();
}

Честно говоря, мне не нравится это решение, потому что оно злоупотребляет концепцией и объектом «таймера» и является возможной тратой системных ресурсов.

1

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector