千家信息网

如何理解C++20新特性协程Coroutines

发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,这篇文章主要讲解了"如何理解C++20新特性协程Coroutines",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"如何理解C++20新特性协程Coro
千家信息网最后更新 2026年11月03日如何理解C++20新特性协程Coroutines

这篇文章主要讲解了"如何理解C++20新特性协程Coroutines",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"如何理解C++20新特性协程Coroutines"吧!

目录
  • 1、co_await

  • 2、awaiter 的三个接口用途

  • 3、协程用法的回顾

想了解上一篇文章内容的小伙伴可点击 C++20 特性 协程 Coroutines (1)

谈到什么是协程. 并且介绍了 co_yield 和 co_return 的作用. 这篇来介绍一下 co_await.

1、co_await

一个形如:

co_await awaitable

的表达式就叫一个 await-expression. co_await 表达式是用来暂停当前协程的运行, 转而等待 awaitable 的结果. 然后 awaitable 进行计算, 最终返回一个 awaiter 结构用来告诉 co_await 要做什么.

co_await 所在的函数块本身就是协程, 所以这个 co_await 也得配上一个 promise 和一个 coroutine_handle. 就像上篇文章里面 generator 类之类的东西.

这个 awaitable 可以是很多东西, 首先会检查 promise 有没有提供 await_transform 函数, 如果有就会用上, 没有就不管.

(只要提供了任何一个 await_transform, 那么每一个 awaitable 都需要找到适合它的重载, 否则就会报错. 库的实现者可以通过 await_transform 接口来限制哪些 awaitable 可以用在协程之中. 参见https://stackoverflow.com/q/65787797/14406396 )

之后的话, 会查找 operator co_await 这个函数, 预期这个 operator 返回一个 awaiter.已经是一个 awaiter 了.

2、awaiter 的三个接口用途

一个 awaiter 需要实现三个接口 await_ready() , await_suspend(std::coroutine_handle

) , await_resume() .

只要实现了这三个接口的东西就是 awaiter.

await_ready() 告诉 co_await 自己好了没.

await_suspend(h) 可以选择返回 void , bool , std::coroutine_handle

之一. h 是本协程的 handle. P是本协程的 promise 类型 (或者是 void, 见第三篇中的解释).

如果 await_ready() 返回 false , 这个协程就会暂停. 之后:

  • 如果 await_suspend(h) 返回类型是 std::coroutine_handle, 那么就会恢复这个 handle. 即运行 await_suspend(h).resume(). 这意味着暂停本协程的时候, 可以恢复另一个协程.

  • 如果 await_suspend(h) 返回类型是 bool, 那么看 await_suspend(h) 的结果, 是 false 就恢复自己.

  • 如果 await_suspend(h) 返回类型是 void, 那么就直接执行. 执行完暂停本协程.

如果 await_ready() 返回 true 或者协程被恢复了, 那么就执行 await_resume() , 它得到的结果就是最终结果.

所以说, 这await_ready, await_suspend, await_resume 三个接口分别表示 "有没有准备好", "停不停", "好了该咋办". 设计还是很自然的.

C++ 的协程是非对称协程, 是有一个调用/被调用的关系的. 一个协程被某个东西唤醒了, 那么它下次暂停的时候, 就会把控制流还给那个唤醒它的东西. 所以 C++ 的协程完全可以看作是一个可重入的函数.

3、协程用法的回顾

再来看上一篇文章中的伪代码

{promise-type promise(promise-constructor-arguments); try {    co_await promise.initial_suspend(); // 创建之后 第一次暂停    function-body // 函数体} catch ( ... ) {    if (!initial-await-resume-called)    throw;     promise.unhandled_exception(); }final-suspend:co_await promise.final_suspend(); // 最后一次暂停}

catch 块里面出现的 !initial-await-resume-called 就是指 promise.initial_suspend() 返回的那个 await_resume() 有没有被执行过.

如果执行了, 那么这个 flag 就会立刻变成 true. 然后调用 promise.unhandled_exception() 来处理异常.

一个例子:

由于 co_await 对这三个东西的应该做什么没有做任何限制, 所以可以用来实现很多功能.

举个例子 (来自标准库), 比如我们想要设计一个协程, 能够停下任意的正时长, 就可以这样设计:

template auto operator co_await(std::chrono::duration d) // operator co_await{    struct awaiter    {        std::chrono::system_clock::duration duration;        awaiter(std::chrono::system_clock::duration d) : duration(d) {}        bool await_ready() const { return duration.count() <= 0; }        int await_resume() {  return 1;  }        void await_suspend(std::coroutine_handle<> h)        {            std::this_thread::sleep_for(duration);        }    };    return awaiter{d};}

这样的话, 如果输入一个正的时间, 就会调用 await_suspend() 进行暂停了. 如果输入的时间是负的, 那就通过 await_ready() 返回 true 绕过了这个过程.

当然, 调用它需要在一个协程中, 也就意味着需要一个 promise 和 coroutine_handle 包装类的配合. 像这样

struct my_future{    struct promise_type;    using handle = std::coroutine_handle;    struct promise_type    {        int current_value;        auto initial_suspend() { return std::suspend_always{}; }        auto final_suspend() { return std::suspend_always{}; }        void unhandled_exception() { std::terminate(); }        /* ... */    };    /* ... */private:    my_future(handle h) : coro(h) {}    handle coro;};my_future sleep_coro(){    printf("Start sleeping\n");    int ans = co_await 1s;    printf("End sleeping, with ans = %d\n", ans);}

当然, 一个函数也可以放在 co_await 的右边, 就像 co_await g(); 只要返回的结构里面有那三个 await_* 接口就行. 甚至你可以直接 co_await std::suspend_always{};

下面是协程流控的细致分析.

int main(){    auto h = sleep_coro(); // 这一步创建协程, 在 co_await initial_suspend 处, 执行完 await_ready, await_suspend. 返回 main// 注意 initial_suspend 返回的是 std::suspend_always{}// 所以是一定暂停, 并且 resume 的时候什么都不做    h.resume();// 这一步执行上一个 await_resume 以后(什么都不做), 执行了 printf("Start sleeping\n");// 然后收到 co_await 1s 返回的结构, 其中 await_suspend 里面需要暂停.// 然后执行完 await_ready, await_suspend (在这个函数里暂停 1s), 返回 main    h.resume();// 这一步执行完 await_resume 以后(初始化 ans = 1)// 执行了 printf("End sleeping, with ans = %d\n", ans);// 然后在 co_await final_suspend 处执行完 await_ready, await_suspend. 就返回 main}

感谢各位的阅读,以上就是"如何理解C++20新特性协程Coroutines"的内容了,经过本文的学习后,相信大家对如何理解C++20新特性协程Coroutines这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!

三个 函数 接口 东西 特性 就是 类型 结果 内容 时候 篇文章 结构 学习 设计 例子 意味 文章 时间 用途 表达式 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 北京互联网科技有限公司 期待互联网科技 互联网与新科技 互联网科技上市公司 互联网女皇 腾讯科技 科技伦理 互联网公司 开启互联网科技时代小说 互联网企业和科技型企业 黑科技闪耀互联网之光 朱啸虎曾投资哪些互联网科技企业 科技互联网海报 广东工业互联网大赛深圳学泰科技 西安有哪些互联网高科技企业 版纳互联网科技选哪家 互联网金融运营模式中的金融科技 兰石爱特工业互联网科技分公司 互联网科技职业技能培训学校 亚光科技低轨卫星互联网 互联网对科技影响 长沙易易互联网科技有限公司 深圳九邦互联网科技有限公司 互联网科技工作委员会 互联网科技有限公司经营范围 期待互联网科技 互联网科技公司官网 济南华为互联网科技产业总部基地 晋城互联网科技 互联网金融科技公司的优势 互联网相关科技技术 颐高云石互联网科技
0