Войти
ПрограммированиеСтатьиОбщее

С++ корутины, начальный уровень (3 стр)

Автор:

1. Как работает Awaiter

+ код


Примитивная корутина - функция Run() которая возвращает тип Task в котором обязательно должен быть тип promise_type.

struct Task {
    struct promise_type {
        Task                get_return_object ()        { return {}; }
        std::suspend_never  initial_suspend () noexcept { return {}; }
        ...
    };
};

Task  Run ()  { co_await Awaiter{}; }

До вызова co_await создается и инициализируется корутина:
1. get_return_object() - создает обертку над корутиной, здесь это не используется.
2. initial_suspend() - возвращает предопределенный тип suspend_never, который сразу запускает выполнение корутины.


Реализация Awaiter:

struct Awaiter
{
    bool  await_ready () const                      { return true; }
    void  await_resume ()                           {}
    void  await_suspend (std::coroutine_handle<>)   {}
};

Порядок вызовов:
3. Конструктор Awaiter, в нем ничего не происходит.
4. Вызывается co_await, который внутри использует Awaiter.
5. Вызов await_ready() - проверяет остановить выполнение корутины или нет, `return true` означает, что корутина продолжит выполнение.
6. Далее вызывается await_resume() - тут может быть любая логика, которая всегда выполнится перед самым возобновлением корутины.

Метод await_suspend() здесь не используется, он вызывается только если await_ready() вернет false.

struct Task {
    struct promise_type {
        ...
        void                return_void ()              {}
        std::suspend_never  final_suspend () noexcept   { return {}; }
    };
};

После вызова co_await корутина продолжает выполнение:
7. Явно или неявно перед выходом из корутины вызывается co_return.
8. co_return вызывает return_void().
9. final_suspend() - вызывается перед удалением корутины, suspend_never - корутина завершается и удаляется, suspend_always - останавливает корутину и нужно явно вызвать std::coroutine_handle<>::destroy().

struct Task {
    struct promise_type {
        void  unhandled_exception ()  {}  

unhandled_exception() вызывается если внутри корутины бросается исключение, в этом примере обработка исключений не реализована.

suspend_never и suspend_always

Данные типы уже реализованы в стандартной библиотеке и отличаются только возвращаемым значением у await_ready().

struct suspend_never {
    constexpr bool  await_ready () const noexcept                     { return true; }
    constexpr void  await_suspend (coroutine_handle<>) const noexcept {}
    constexpr void  await_resume () const noexcept                    {}
};

struct suspend_always {
    constexpr bool  await_ready () const noexcept                     { return false; }
    constexpr void  await_suspend (coroutine_handle<>) const noexcept {}
    constexpr void  await_resume () const noexcept                    {}
};
Страницы: 1 2 3 4 58 Следующая »

#coroutine, #C++

7 ноября 2022

Комментарии [58]