Что происходит, когда сопрограмма возвращается в приостановленную сопрограмму?

Предположим, у меня есть две сопрограммы: coroutine_a и coroutine_b. В coroutine_a он вызывает:

co_await awaiter_a;

awaiter_a::await_suspend возвращает обработчик сопрограммы coroutine_b. В результате coroutine_b возобновляется. Затем в coroutine_b он вызывает:

co_await awaiter_b;

awaiter_b::await_suspend возвращает недействительность. В результате управление должно быть возвращено вызывающей стороне/возобновляющей стороне coroutine_a. Что произойдет, когда управление вернется к coroutine_a?

Я думаю, что есть два варианта:

  1. coroutine_a возвращается к вызывающему абоненту.
  2. coroutine_a остается приостановленным, пока кто-нибудь не возобновит его.

Какой из них правильный? Или что-то еще?

Симметричная передача означает, что когда `await_suspend` coroutine_a возвращает coroutine_b, coroutine_a покидает изображение, и его вызывающая сторона становится вызывающей coroutine_b.

Raymond Chen 08.06.2024 07:06

@RaymondChen Похоже, это может быть ответом.

Ted Lyngmo 08.06.2024 08:21

@RaymondChen Спасибо за ответ. Это именно то, чего я хочу.

Machearn 08.06.2024 20:53
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
3
94
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

co_await awaiter_a;

Запись этого кода в функцию означает, что функция ожидает значения, которое будет сгенерировано awaiter_a. Следовательно, этой текущей функции не разрешено продолжать работу до тех пор, пока awaiter_a не сгенерирует это значение.

Если await_suspend возвращает дескриптор сопрограммы, это означает, что выполнение продолжается в этом дескрипторе сопрограммы. Однако это не меняет смысла приостановки; текущая сопрограмма остановится до тех пор, пока awaiter_a не будет готова выдать значение.

Фактически это означает, что новый дескриптор (из вашего coroutine_b) заменяет текущий дескриптор (из вашего coroutine_a, который только что приостановился).

Если await_suspend ничего не возвращает, это просто приостанавливает работу сопрограммы. Поэтому, когда coroutine_b выполняет co_await, он приостанавливается. Но это все. Поток управления продолжается от вызывающей стороны coroutine_a, как если бы coroutine_a был приостановлен... потому что он был и до сих пор приостановлен.

Ответ принят как подходящий

Это объясняется [expr.await]/5:

Выражение-await оценивает (возможно, преобразованное) выражение o и выражение await-ready, затем:

  • Если результат await-ready равен false, сопрограмма считается приостановленной. Затем:

    • Если тип await-suspend равен std​::​coroutine_handle<Z>, оценивается await-suspend.resume().
      [Примечание 1: Это возобновляет сопрограмму, на которую ссылается результат ожидания-приостановки. Таким образом можно последовательно возобновлять любое количество сопрограмм, в конечном итоге возвращая поток управления текущему вызывающему или возобновляющему сопрограмму ([dcl.fct.def.coroutine]). — последнее примечание]
    • В противном случае, если тип await-suspend равен bool, оценивается await-suspend, и выполнение сопрограммы возобновляется, если результат равен false.
    • В противном случае оценивается await-suspend.

    Если вычисление await-suspend завершается через исключение, исключение перехватывается, сопрограмма возобновляется, и исключение немедленно генерируется повторно ([Exception.throw]). В противном случае поток управления возвращается к текущему вызывающему или возобновляющему сопрограмму ([dcl.fct.def.coroutine]) без выхода из каких-либо областей ([stmt.jump]). Точка в сопрограмме непосредственно перед возвратом управления к вызывающему или возобновляющему объекту является точкой приостановки сопрограммы.

  • Если результатом await-ready является true или когда сопрограмма возобновляется не путем повторного создания исключения из await-suspend, вычисляется выражение await-resume, и его результатом является результат await-expression.

Итак, co_await awaiter_a сначала приостанавливает сопрограмму A, затем переходит к первому подпункту и вызывает .resume() дескриптор сопрограммы B. Когда сопрограмма B приостанавливается и возвращает управление сопрограмме A, то мы только что завершили второй подпункт в сопрограмме A, который означает, что мы переходим к абзацу в конце первого маркера, и поток управления возвращается к вызывающему или возобновляющему сопрограмму A.

(Примечание 1 также объясняет это. Возврат дескриптора сопрограммы из await-suspend по сути просто вставляет сопрограмму в начало очереди, которую нужно возобновить, перед сопрограммой, которая в противном случае была бы возобновлена, если бы await-suspend имел тип void.)

Другие вопросы по теме