Как сделать асинхронное программирование на C++ более линейным (сопрограммы?)
В C++14 я хотел бы создать механизм для использования асинхронных API "последовательным" способом, используя один поток.
Чтобы быть более явным, я хотел бы добиться что-то вроде этого:
// Transform AsyncOp1 into SyncOp1
// SyncOp1 returns after AsyncOp1 completes
// but yields execution to another script
void SyncOp1()
{
AsyncOp1( [](){ // async op completion handler
// TODO: yield control
} );
// TODO: control returns here after AsyncOp1 completed
}
... // similar code for SyncOp2, SyncOp3, SyncOp4,...
void Script1()
{
SyncOp1();
SyncOp2(); // SyncOp2 starts only after AsyncOp1 has completed
...
}
void Script2()
{
SyncOp3();
SyncOp4(); // SyncOp4 starts only after AsyncOp3 has completed
...
}
int main()
{
...
Spawn( Script1 );
Spawn( Script2 ); // Script1 and Script2 runs in parallel
...
// TODO some machinery here :-)
...
return 0;
}
Моя программа должна запускать несколько сценариев одновременно, и каждый сценарий должен представлять собой последовательность стандартных вызовов функций (SyncOpX
). Сценарии могут работать параллельно, потому что SyncOpX
реализованы в терминах асинхронных функций (т. е. функций, которые запускают операции ввода-вывода, возвращают и вызывают обратные вызовы после завершения ввода-вывода).
Конечно, было бы легко найти решение, используя несколько потоков (Spawn
создает новую тему и SynchOpX
ждет результата асинхронного вызова). Но вместо этого я ищу решение с одним потоком.
Я думаю, что сопрограммы могут быть использованы в некотором роде. Поскольку текущий стандарт C++14
Есть ли решение с boost coroutines
? Или с любым другим [переносным] механизмом?
Кстати, я использую boost::asio
для асинхронного ввода / вывода.
Благодарю.
1 ответ
Если вы уже используете boost.asio, вы должны рассмотреть его spawn() и yield_context - http://www.boost.org/doc/libs/1_63_0/doc/html/boost_asio/reference.html
Дополнительно вы можете рассмотреть boost.fiber:
"Одним из основных преимуществ Boost.Fiber является возможность использовать асинхронные операции для повышения эффективности, и в то же время структурировать вызывающий код, как если бы операции были синхронными".