Programarea Asincronă cu Coroutine, co_await și co_yield în C++20 în C++

Ghid fundamental pentru arhitectura coroutinelor în C++20: înțelegerea funcțiilor suspendabile fără stack (stackless coroutines), rolul tipurilor promisiune (promise_type), coroutine_handle și cuvintele cheie co_await, co_yield și co_return.

Sintaxă
co_await operator | co_yield valoare | co_return rezultat | struct Task { struct promise_type ... };

În programarea clasică C++, o funcție are două puncte fundamentale: este apelată și returnează o valoare, stiva sa locală de variabile fiind distrusă definitiv la ieșire. Coroutinele din C++20 sunt funcții care pot fi suspendate voluntar în mijlocul execuției și reluate ulterior exact din punctul în care s-au oprit, păstrându-și starea intactă. Coroutinele C++ sunt fără stivă (Stackless): variabilele lor locale sunt stocate pe heap într-un frame compact alocat de compilator, permițând crearea a milioane de coroutine concurente cu un consum minim de memorie.

Cele Trei Cuvinte Cheie ale Coroutinelor:

  • co_await <expresie>: Suspendă execuția coroutinei până când o operațiune asincronă (de exemplu un apel de rețea, un timer sau o interogare disc) este finalizată.
  • co_yield <valoare>: Suspendă coroutina și transmite o valoare intermediară către apelant (stă la baza generatoarelor de secvențe).
  • co_return <valoare>: Finalizează execuția coroutinei și returnează rezultatul final.
Structura minimă a unei Coroutine Task în C++20
#include <coroutine>
#include <print>

// Tipul returnat de o coroutină trebuie să definească un 'promise_type':
struct TaskSimplu {
    struct promise_type {
        TaskSimplu get_return_object() {
            return TaskSimplu{std::coroutine_handle<promise_type>::from_promise(*this)};
        }
        std::suspend_always initial_suspend() noexcept { return {}; }
        std::suspend_always final_suspend() noexcept { return {}; }
        void return_void() noexcept {}
        void unhandled_exception() { std::terminate(); }
    };

    std::coroutine_handle<promise_type> handle;
    ~TaskSimplu() { if (handle) handle.destroy(); }
};

TaskSimplu coroutinaDemonstrativa() {
    std::println("Pasul 1: Coroutina a inceput.");
    co_await std::suspend_always{}; // Se suspenda voluntar!
    std::println("Pasul 2: Coroutina a fost reluata cu succes!");
}

int main() {
    auto task = coroutinaDemonstrativa();
    std::println("Main: Coroutina este suspendata. Facem alte calcule...");
    // Reluăm manual coroutina:
    task.handle.resume();
    return 0;
}