C++协程

1. 什么是协程

协程就是一段可以挂起(suspend)和恢复(resume)的程序,一般而言,就是一个支持挂起和恢复的函数。

  • 函数挂起:函数执行到某个位置后,可以停止执行当前函数,并将控制权转移给其他函数(注意,此处的转移不是 return,会记录当前函数的状态(协程状态coroutine state),如输入参数,使用到的变量(变量是值拷贝还是引用或指针,引用和指针需要程序员确保变量的生命周期),控制权转移的位置等)。
  • 函数恢复:再次进入到该函数时,查询函数的执行状态,从上一次转移的位置继续执行。

在C++中,函数的挂起和恢复都是由编译器完成的,程序员只需要关注什么时候挂起以及恢复的时机。当协程执行完成后或被外部主动销毁,协程的资源会被释放。注意不要访问已经被释放的资源。

2. 协程的挂起与恢复

2.1 关键字
  • co_yield: 挂起协程,将协程中的某个数值传递给协程的调用者。
  • co_await: 重点在挂起自己,等待其他协程或异步操作完成(也可以实现与 co_yield 相同的效果)。
  • co_return: 协程函数执行结束返回。
2.2 协程的等待体 Awaiter

Awaiter 是一个对象,用于实现协程的挂起和恢复。一个 Awaiter 对象必须提供以下三个函数:

  1. bool await_ready():

    co_yieldco_await 会先调用该方法,如果返回 false 则协程挂起,如果返回 true,则协程不会挂起,而是继续执行。
  2. auto await_suspend(std::coroutine_handle<> coroutine_handle):

    • await_ready 返回 false 后,协程正常挂起时调用该方法,允许在该函数内重新恢复协程。
    • 返回值类型:

         void:将执行权返回给协程的调用者或恢复者。

         true:与 void 相同。

         false:表示当前协程恢复执行。

         std::coroutine_handle<>:表示恢复 coroutine_handle 所指向的协程。

              3.抛出异常:此时当前协程会恢复执行,并在当前协程中抛出异常。

  3.auto await_resume():

     co_await 调用对象的返回值。

#include 
#include 
#include 

struct Task {
    struct promise_type {
        Task get_return_object() {
            return Task{ std::coroutine_handle::from_promise(*this) };
        }
        std::suspend_never initial_suspend() { return {}; }
        std::suspend_always final_suspend() noexcept { return {}; }
        void return_void() {}
        void unhandled_exception() { std::terminate(); }
    };

    std::coroutine_handle coro;
    Task(std::coroutine_handle h) : coro(h) {}
    ~Task() { if (coro) coro.destroy(); }
};

struct Awaiter {
    bool await_ready() { return false; }
    void await_suspend(std::coroutine_handle<> h) {
        std::cout << "Suspending...\n";
        h.resume();
    }
    void await_resume() { std::cout << "Resuming...\n"; }
};

Task exampleCoroutine() {
    std::cout << "Starting coroutine...\n";
    co_await Awaiter{};
    std::cout << "Continuing coroutine...\n";
    co_yield;
    std::cout << "Yielded and resumed...\n";
    co_return;
}

int main() {
    auto task = exampleCoroutine();
    task.coro.resume();
    return 0;
}

你可能感兴趣的:(c++协程学习,c++,开发语言)