讲师中心 微信公众号
AI工具推荐 视频效率加速

c++20 coroutine用法 c++如何使用协程进行异步编程

云宇姑娘_3308

云宇姑娘_3308

发布时间:2026-03-17 18:42:54

|

758人浏览过

|

来源于php中文网

原创

协程不是线程,co_await仅挂起/恢复控制流而不并发;实现异步需手动集成OS或库(如asio),并正确实现awaiter三函数;std::generator更安全但只支持co_yield;调试须严防非法resume和悬垂引用。

c++20 coroutine用法 c++如何使用协程进行异步编程

协程不是线程,co_await 不会自动并发

很多人一看到 co_await 就以为“这下能并行了”,结果发现 IO 还是串着跑、CPU 密集任务卡死主线程。C++20 协程本身不带调度器,co_await 只是挂起/恢复控制流,不启动新线程,也不切换栈——它只是让函数能中途暂停、稍后继续,类似生成器。

真正异步 IO(比如读文件、发 HTTP)需要你手动把操作交给 OS 或第三方库(如 libuv、asio),然后让 awaiter 在操作完成时通知协程恢复。否则写个 co_await some_io_op(),而 some_io_op() 内部还是阻塞调用,那就白搭。

  • 别指望 std::this_thread::sleep_for 配 co_await 实现“非阻塞延时”——它照样阻塞线程;要用 asio::steady_timer 一类可 await 的定时器
  • 如果你用的是 std::experimental::coroutine_handle 手写 promise,必须自己保证 resume 被调用在线程安全的上下文中,否则容易崩溃
  • MSVC 和 GCC 对协程的支持细节不同:GCC 12+ 默认需 -fcoroutines,MSVC 19.30+ 要 /std:c++20 /await,漏掉编译开关会报 co_await 未声明

怎么写一个可 co_await 的类型?关键在 await_ready、await_suspend、await_resume

不是所有对象都能直接 co_await,必须满足“awaiter 概念”:提供这三个成员函数。它们决定协程何时挂起、挂到哪、恢复后返回什么。

常见错误是把 await_suspend 返回 true 却没手动 resume,导致协程永远挂起;或者返回 void(即同步完成),却在 await_resume 里抛异常,结果异常被吞掉。

立即学习“C++免费学习笔记(深入)”;

  • await_ready() 返回 true → 协程不挂起,直接执行后续代码;返回 false → 进入挂起流程
  • await_suspend(handle) 若返回 std::coroutine_handle{},表示由你接管 resume 时机;若返回 void,系统会在当前线程立刻 resume(等价于同步)
  • await_resume() 的返回值就是 co_await expr 的结果,类型必须和它声明的一致,否则编译失败

示例(简化版延迟 awaiter):

C++14
C++14

C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。

下载
struct delay_awaiter {
  bool await_ready() const noexcept { return false; }
  void await_suspend(std::coroutine_handle<> h) {
    // 把 h 交给 timer 回调,比如 asio::steady_timer::async_wait
  }
  int await_resume() const noexcept { return 42; }
};

用 std::generator 做数据流比手写协程更安全

如果你只是想按需生成一系列值(比如遍历树、解析大文件行、分页查数据库),std::generator<t></t> 是 C++23 标准化前最稳的选择——它基于协程,但屏蔽了 promise、awaiter 等底层细节,且 MSVC/GCC/Clang 都已支持(需开启 C++20)。

相比自己实现 promise_type,std::generator 自动管理内存和生命周期,不会因忘记 final_suspend 返回 std::suspend_always 而导致析构时 crash。

  • 不能在 std::generator 函数里捕获局部变量引用并 yield 出去,因为协程帧可能在 yield 后销毁,引用变悬垂
  • 每个 std::generator 对象只能遍历一次,重复 begin() 不会重放;需要多次遍历得重新构造
  • 它不支持 co_await,只支持 co_yield;想混用 await 和 yield?得自己写 promise_type

调试协程崩溃时,优先检查 coroutine_handle::done() 和 resume() 调用时机

协程崩溃最常见的原因是 resume 已结束的协程,或对空 handle 调用 resume()。而 coroutine_handle::done() 并非线程安全——多线程环境下它可能刚返回 false,协程就在另一线程里结束了。

不要靠 if (!h.done()) h.resume(); 来防护,这有竞态。正确做法是:resume 前确保 handle 有效,且仅由约定好的一方负责 resume(比如 IO 完成回调);如果需要多处可能 resume,用原子状态标记 + CAS 控制。

  • GDB/LLDB 对协程帧支持有限:bt 可能看到 operator co_await 但看不到原始调用点,建议在关键 awaiter 里加日志或断点
  • ASan 能捕获协程帧内的 use-after-free,但无法检测跨协程的逻辑错误(比如忘了 resume)
  • Release 模式下,coroutine_handle::from_address(nullptr) 不会报错,但后续 resume 必崩——务必初始化 handle 为 nullptr 并判空

协程的复杂性不在语法,而在控制流分散后责任边界的模糊。谁创建、谁挂起、谁 resume、谁销毁,这几个问题没理清,代码越写越像定时炸弹。

相关文章

c++速学教程(入门到精通)
c++速学教程(入门到精通)

c++怎么学习?c++怎么入门?c++在哪学?c++怎么学才快?不用担心,这里为大家提供了c++速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

c++

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

Loomy
Loomy Hot

一款AI工具,主要用于科大讯飞发布的桌面级 AI 助理,比 OpenClaw 更易用、更安全!,适合需要提升相关任务效率的用户。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

码上飞
码上飞 Hot

一款基于自然语言的AI应用开发平台,可根据用户描述自动生成应用程序,帮助个人和团队快速完成应用原型与开发。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

PixTV
PixTV Hot

PixTV是一款面向AIGC内容创作的AI视频生成工具。

UP简历
UP简历 Hot

一款AI办公效率工具,主要用于基于AI技术的免费在线简历制作工具,适合需要提升相关任务效率的用户。

Laper
Laper Hot

Laper是专为编剧、导演和制片人推出的 AI 原生剧本创作工具。

蛙蛙写作

一款AI论文写作工具,主要用于超级AI智能写作助手,适合需要提升相关任务效率的用户。

相关专题

更多
javascriptvoid(o)怎么解决
javascriptvoid(o)怎么解决

javascriptvoid(o)的解决办法:1、检查语法错误;2、确保正确的执行环境;3、检查其他代码的冲突;4、使用事件委托;5、使用其他绑定方式;6、检查外部资源等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

636

2023.11.23

java中void的含义
java中void的含义

本专题整合了Java中void的相关内容,阅读专题下面的文章了解更多详细内容。

371

2025.11.27

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

6607

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

2748

2023.08.10

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

4638

2023.08.10

Python 多线程与异步编程实战
Python 多线程与异步编程实战

本专题系统讲解 Python 多线程与异步编程的核心概念与实战技巧,包括 threading 模块基础、线程同步机制、GIL 原理、asyncio 异步任务管理、协程与事件循环、任务调度与异常处理。通过实战示例,帮助学习者掌握 如何构建高性能、多任务并发的 Python 应用。

1289

2025.12.24

java多线程相关教程合集
java多线程相关教程合集

本专题整合了java多线程相关教程,阅读专题下面的文章了解更多详细内容。

443

2026.01.21

C++多线程相关合集
C++多线程相关合集

本专题整合了C++多线程相关教程,阅读专题下面的的文章了解更多详细内容。

579

2026.01.21

DBeaver怎么导入数据
DBeaver怎么导入数据

DBeaver数据导入专题,整理Excel、CSV、SQL、TXT等常见文件的数据导入方法,涵盖目标数据库选择、数据表创建、字段映射、数据类型设置及导入参数配置等操作,帮助用户将本地文件中的数据写入数据库,并了解批量导入、重复数据处理和导入失败等常见问题的解决方法。

0

2026.11.05

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C++ Core Guidelines
C++ Core Guidelines

共0课时 | 0人学习

C++ Reference
C++ Reference

共0课时 | 0人学习

C++ 官方标准说明
C++ 官方标准说明

共0课时 | 0人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn