При каждом вызове co_await
приостанавливается только сопрограмма верхнего уровня.Чтобы приостановить более низкий уровень, этот уровень должен приостановить себя явно.И на тот момент, это сейчас текущий «верхний уровень».Поэтому в каждом случае приостанавливается только текущий верхний уровень.
Сравните это с чисто гипотетической библиотекой стековых сопрограмм:
//This function will always print the same thread ID.
void secondLevel(int id)
{
while(!toBackgroundThread.poll())
suspend_coroutine();
cout << id << " run on " << this_thread::get_id() << endl;
while(!toBackgroundThread.poll())
suspend_coroutine();
cout << id << " run on " << this_thread::get_id() << endl;
}
void topLevel() {
secondLevel(1);
secondLevel(2);
}
void listen(AsyncQueue& queue) {
while (true) {
if (!queue.poll()) {
this_thread::sleep_for(100ms);
}
}
}
int main() {
thread([]() {
listen(toBackgroundThread);
}).detach();
auto coro = create_coroutine(topLevel);
coro.switch_to();
toMainThread.ready(); //Notes that the main thread is waiting
while (true) {
if (!toMainThread.poll()) {
coro.switch_to();
}
}
};
topLevel
не имеет явного механизма приостановки.И все же его выполнение приостанавливается всякий раз, когда любая вызываемая им функция приостанавливает выполнение.Весь стек вызовов, определенный функцией, данной create_coroutine
, и все, что он вызывает, приостанавливается.Вот как работает стековая сопрограмма.
Это то, с чем противопоставляется, когда речь идет о сопрограммах без стека.В версии без стека каждая функция, которая должна быть приостановлена, должна быть специально закодирована , чтобы сделать это.И, таким образом, больше не является «общим назначением»;теперь он специально предназначен для сценариев приостановки.