C++ 协程(Coroutine)使用教程:从基础概念到实战应用
一、什么是协程协程Coroutine是一种能够在执行过程中暂停、随后再恢复执行的函数。与普通函数不同协程可以在某个点挂起把控制权交还给调用者之后又能从挂起点继续执行。这种特性使得协程非常适合处理异步 I/O、生成器、惰性求值等场景。C20 将协程正式纳入标准库提供了一套底层的协程框架。需要注意的是C20 标准库只提供了协程的基础设施关键字和编译器支持包括三个新关键字co_await挂起当前协程等待某个操作完成co_yield挂起协程并返回一个值co_return结束协程并返回最终值要使用 C20 协程编译器需至少支持 C20 标准。主流编译器如 GCC 10、Clang 13、MSVC 2019 16.8 均已提供支持。二、C 协程的基础组件C20 协程模型由几个核心组件构成。理解这些组件是掌握协程编程的关键。2.1 promise_type每个协程都与一个 promise_type 对象关联该对象负责控制协程的行为。promise_type 需要实现以下核心方法get_return_object()创建协程的返回值对象initial_suspend()定义协程开始执行时的行为是立即执行还是先挂起final_suspend()定义协程结束时的行为通常用于对称转移unhandled_exception()处理协程中未捕获的异常return_void()或return_value()处理 co_return 的值2.2 协程返回类型与 Awaitable协程的返回类型必须是满足特定要求的类或结构体其中必须定义一个嵌套类型 promise_type。此外一个可等待对象Awaitable需要实现三个方法await_ready()检查操作是否已经完成返回 true 时不挂起await_suspend()在协程挂起时调用可接收协程句柄await_resume()协程恢复时调用返回最终结果标准库还提供了两个预定义的 Awaitablestd::suspend_always和std::suspend_never分别表示始终挂起和永不挂起。三、基本协程实现示例下面通过一个简单但完整的例子来展示 C 协程的各个组成部分如何协同工作。3.1 一个最简单的生成器首先实现一个基本协程返回类型它允许协程挂起和执行#include coroutine #include iostream struct Task { struct promise_type { Task get_return_object() { return Task{std::coroutine_handlepromise_type::from_promise(*this)}; } std::suspend_never initial_suspend() { return {}; } std::suspend_never final_suspend() noexcept { return {}; } void return_void() {} void unhandled_exception() {} }; std::coroutine_handlepromise_type handle; Task(std::coroutine_handlepromise_type h) : handle(h) {} ~Task() { if (handle) handle.destroy(); } }; Task hello_coroutine() { std::cout Hello, Coroutine! std::endl; co_return; } int main() { auto task hello_coroutine(); std::cout Back in main std::endl; return 0; }3.2 理解 co_await 和挂起语义接下来扩展前面的例子展示 co_await 如何挂起和恢复协程#include coroutine #include iostream #include thread #include chrono struct Task { struct promise_type { Task get_return_object() { return Task{std::coroutine_handlepromise_type::from_promise(*this)}; } std::suspend_never initial_suspend() { return {}; } std::suspend_never final_suspend() noexcept { return {}; } void return_void() {} void unhandled_exception() {} }; std::coroutine_handlepromise_type handle; Task(std::coroutine_handlepromise_type h) : handle(h) {} ~Task() { if (handle) handle.destroy(); } }; // 自定义 Awaitable模拟异步延时 struct AsyncDelay { int milliseconds; bool await_ready() const { return false; } void await_suspend(std::coroutine_handle h) { std::thread([h, ms milliseconds]() { std::this_thread::sleep_for(std::chrono::milliseconds(ms)); h.resume(); }).detach(); } void await_resume() {} }; Task async_task() { std::cout 协程开始执行... std::endl; std::cout 等待 1 秒... std::endl; co_await AsyncDelay{1000}; std::cout 等待 2 秒... std::endl; co_await AsyncDelay{2000}; std::cout 协程执行完毕 std::endl; } int main() { auto task async_task(); std::cout 主线程继续执行其他任务... std::endl; // 等待足够时间以确保协程完成 std::this_thread::sleep_for(std::chrono::milliseconds(3500)); return 0; }四、co_yield 实现生成器co_yield 允许协程在挂起时返回一个值非常适合实现惰性生成器。下面的例子展示如何用协程实现一个整数序列生成器#include coroutine #include iostream #include optional templatetypename T struct Generator { struct promise_type { std::optionalT current_value; Generator get_return_object() { return Generator{std::coroutine_handlepromise_type::from_promise(*this)}; } std::suspend_always initial_suspend() { return {}; } std::suspend_always final_suspend() noexcept { return {}; } std::suspend_always yield_value(T value) { current_value std::move(value); return {}; } void return_void() {} void unhandled_exception() {} }; std::coroutine_handlepromise_type handle; Generator(std::coroutine_handlepromise_type h) : handle(h) {} ~Generator() { if (handle) handle.destroy(); } Generator(const Generator) delete; Generator operator(const Generator) delete; Generator(Generator other) noexcept : handle(other.handle) { other.handle nullptr; } std::optionalT next() { if (!handle || handle.done()) { return std::nullopt; } handle.resume(); if (handle.done()) { return std::nullopt; } return handle.promise().current_value; } }; Generatorint fibonacci(int count) { int a 0, b 1; for (int i 0; i count; i) { co_yield a; int temp a b; a b; b temp; } } int main() { auto gen fibonacci(10); while (auto val gen.next()) { std::cout *val ; } std::cout std::endl; // 输出0 1 1 2 3 5 8 13 21 34 return 0; }五、协程与异常处理协程中的异常处理需要特别注意。promise_type 中的 unhandled_exception() 方法负责处理协程内部抛出的异常。以下示例展示了完整的异常处理机制#include coroutine #include iostream #include exception struct SimpleTask { struct promise_type { std::exception_ptr exception; SimpleTask get_return_object() { return SimpleTask{std::coroutine_handlepromise_type::from_promise(*this)}; } std::suspend_never initial_suspend() { return {}; } std::suspend_never final_suspend() noexcept { return {}; } void return_void() {} void unhandled_exception() { exception std::current_exception(); } }; std::coroutine_handlepromise_type handle; SimpleTask(std::coroutine_handlepromise_type h) : handle(h) {} ~SimpleTask() { if (handle) handle.destroy(); } void get_result() { if (handle.promise().exception) { std::rethrow_exception(handle.promise().exception); } } }; SimpleTask may_throw(bool should_throw) { if (should_throw) { throw std::runtime_error(协程内部抛出的异常); } std::cout 协程正常执行 std::endl; co_return; } int main() { auto task1 may_throw(false); try { task1.get_result(); std::cout task1 执行成功 std::endl; } catch (const std::exception e) { std::cout 捕获异常 e.what() std::endl; } auto task2 may_throw(true); try { task2.get_result(); } catch (const std::exception e) { std::cout 捕获异常 e.what() std::endl; } return 0; }六、实战异步文件读取器结合以上知识我们来构建一个更贴近实战的例子——使用协程实现异步文件读取。这个例子展示了协程在 I/O 密集型任务中的实际应用#include coroutine #include iostream #include fstream #include string #include thread #include future #include vector // 异步任务返回类型 struct AsyncTask { struct promise_type { std::string result; AsyncTask get_return_object() { return AsyncTask{std::coroutine_handlepromise_type::from_promise(*this)}; } std::suspend_always initial_suspend() { return {}; } std::suspend_always final_suspend() noexcept { return {}; } void return_value(std::string value) { result std::move(value); } void unhandled_exception() {} }; std::coroutine_handlepromise_type handle; AsyncTask(std::coroutine_handlepromise_type h) : handle(h) {} ~AsyncTask() { if (handle) handle.destroy(); } AsyncTask(const AsyncTask) delete; AsyncTask operator(const AsyncTask) delete; AsyncTask(AsyncTask other) noexcept : handle(other.handle) { other.handle nullptr; } std::string get_result() { if (!handle.done()) { handle.resume(); } if (!handle.done()) { return ; // 尚未完成 } return handle.promise().result; } }; // 异步文件读取 Awaitable struct AsyncReadFile { std::string filename; std::shared_ptrstd::string buffer; bool await_ready() const { return false; } void await_suspend(std::coroutine_handle h) { std::thread([this, h]() { std::ifstream file(filename); if (file.is_open()) { std::stringstream ss; ss file.rdbuf(); *buffer ss.str(); } h.resume(); }).detach(); } std::string await_resume() { return *buffer; } }; AsyncTask read_files() { std::cout 开始异步读取文件... std::endl; auto buf1 std::make_sharedstd::string(); std::string content1 co_await AsyncReadFile{file1.txt, buf1}; std::cout 文件 1 读取完毕大小 content1.size() 字节 std::endl; auto buf2 std::make_sharedstd::string(); std::string content2 co_await AsyncReadFile{file2.txt, buf2}; std::cout 文件 2 读取完毕大小 content2.size() 字节 std::endl; std::string result 合并内容\n content1 \n---\n content2; co_return result; }七、协程调度与对称转移在高性能协程框架中对称转移Symmetric Transfer是一个重要的优化技术。它允许协程在挂起时直接跳转到另一个协程而不需要先返回调度器从而减少了多余的上下文切换开销。对称转移的核心在于 final_suspend 返回一个 std::coroutine_handle告诉编译器应该继续执行哪个协程#include coroutine #include iostream struct SymmetricTask { struct promise_type { std::coroutine_handle continuation; SymmetricTask get_return_object() { return SymmetricTask{std::coroutine_handlepromise_type::from_promise(*this)}; } std::suspend_always initial_suspend() { return {}; } auto final_suspend() noexcept { // 对称转移协程结束时跳转到 continuation struct FinalAwaiter { std::coroutine_handle continuation; bool await_ready() noexcept { return false; } std::coroutine_handle await_suspend(std::coroutine_handle) noexcept { return continuation; } void await_resume() noexcept {} }; return FinalAwaiter{continuation}; } void return_void() {} void unhandled_exception() {} }; std::coroutine_handlepromise_type handle; SymmetricTask(std::coroutine_handlepromise_type h) : handle(h) {} ~SymmetricTask() { if (handle) handle.destroy(); } };通过这种方式可以实现高效的任务调度避免传统回调地狱同时在性能关键场景中减少不必要的开销。八、常用协程库推荐C20 只提供了协程的底层原语实际开发中建议使用成熟的第三方库来简化协程编程cppcoro一个流行的 C 协程库提供了生成器、任务、异步 I/O 等多种实用工具帮助开发者快速上手协程编程Boost.Coroutine2Boost 库中的协程组件支持 C14 及以上标准提供堆栈式协程实现libunifexFacebook 出品的异步编程框架基于 Sender/Receiver 模型深度集成 C20 协程folly::coroMetaFacebook开源的高性能协程库适用于大规模分布式系统中的异步任务管理C20 协程为异步编程提供了一种优雅且强大的表达方式。以下是几点最佳实践建议生命周期管理始终注意协程句柄的销毁避免内存泄漏。建议使用 RAII 模式封装 coroutine_handle异常处理在 promise_type 中妥善处理 unhandled_exception避免程序因未捕获异常而终止性能考量在高频调用的场景中优先使用对称转移技术减少不必要的调度开销使用成熟库避免从零开始实现协程基础设施善用 cppcoro 等社区验证过的方案避免过度使用并非所有场景都适合使用协程简单的同步调用有时更清晰易维护掌握 C 协程需要一定的学习曲线但一旦理解其核心机制就能编写出简洁、高效且易于维护的异步代码。

相关新闻

【小程序课程设计/毕业设计】基于微信小程序的校园餐饮外卖订餐系统 校园食堂智能点餐与评价管理平台【附源码、数据库、万字文档】

【小程序课程设计/毕业设计】基于微信小程序的校园餐饮外卖订餐系统 校园食堂智能点餐与评价管理平台【附源码、数据库、万字文档】

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/7/20 17:00:48阅读更多 →
【小程序课程设计/毕业设计】基于 SpringBoot 的音乐资源智能推荐系统 融合用户行为的协同过滤音乐推荐系统 智能音乐点播与个性化推荐服务系统【附源码、数据库、万字文档】

【小程序课程设计/毕业设计】基于 SpringBoot 的音乐资源智能推荐系统 融合用户行为的协同过滤音乐推荐系统 智能音乐点播与个性化推荐服务系统【附源码、数据库、万字文档】

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/7/20 17:00:48阅读更多 →
【小程序课程设计/毕业设计】基于 Android 的便民在线医疗服务平台 互联网在线诊疗预约服务系统的设计与实现【附源码、数据库、万字文档】

【小程序课程设计/毕业设计】基于 Android 的便民在线医疗服务平台 互联网在线诊疗预约服务系统的设计与实现【附源码、数据库、万字文档】

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/7/20 17:00:48阅读更多 →
3步搞定B站缓存视频合并:告别碎片化,享受完整离线观看体验

3步搞定B站缓存视频合并:告别碎片化,享受完整离线观看体验

3步搞定B站缓存视频合并:告别碎片化,享受完整离线观看体验 【免费下载链接】BilibiliCacheVideoMerge 🔥🔥Android上将bilibili缓存视频合并导出为mp4,支持安卓5.0 ~ 13,视频挂载弹幕播放(Android consolid…

2026/7/21 9:29:29阅读更多 →
中小企业统一身份认证系统(IAM)架构与实战指南

中小企业统一身份认证系统(IAM)架构与实战指南

1. 统一身份认证系统的核心价值解析 对于50人以下的中小科技企业而言,IT系统往往呈现"烟囱式"发展态势。市场部的同事需要维护CRM账号,研发团队要管理GitLab权限,财务部门又有独立的ERP系统,每个业务系统都维护着独立的…

2026/7/21 9:29:29阅读更多 →
日本制造业AI落地难的三大组织惯性与破局实践

日本制造业AI落地难的三大组织惯性与破局实践

1. 项目概述:当“技术立国”的日本在AI赛道上突然失速你有没有注意过这样一个反差?东京地铁的自动检票闸机精准到毫秒,工厂里的机械臂焊接精度比人眼还稳,连便利店饭团的保质期管理都靠算法动态调整——日本在精密制造、自动化控制…

2026/7/21 9:29:29阅读更多 →
5分钟实现Android Studio中文界面:告别英文困扰的终极汉化指南

5分钟实现Android Studio中文界面:告别英文困扰的终极汉化指南

5分钟实现Android Studio中文界面:告别英文困扰的终极汉化指南 【免费下载链接】AndroidStudioChineseLanguagePack AndroidStudio中文插件(官方修改版本) 项目地址: https://gitcode.com/gh_mirrors/an/AndroidStudioChineseLanguagePack 还在为…

2026/7/21 9:29:29阅读更多 →
如何快速掌握Mihon插件开发:漫画阅读器扩展的终极指南

如何快速掌握Mihon插件开发:漫画阅读器扩展的终极指南

如何快速掌握Mihon插件开发:漫画阅读器扩展的终极指南 【免费下载链接】mihon Free and open source manga reader for Android 项目地址: https://gitcode.com/gh_mirrors/mi/mihon Mihon是一款免费开源的Android漫画阅读器应用,通过强大的插件系…

2026/7/21 9:29:29阅读更多 →
LangGraph:AI Agent系统的状态管理与故障恢复关键

LangGraph:AI Agent系统的状态管理与故障恢复关键

1. 为什么LangGraph才是AI Agent系统的生存关键当开发者第一次接触LangChain时,往往会被其快速搭建AI应用的能力所震撼。确实,LangChain通过预制组件和标准化接口,让一个基础AI应用的开发时间从周级别缩短到小时级别。但真正经历过生产环境考…

2026/7/21 9:27:26阅读更多 →
Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/21 0:51:49阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/21 0:51:49阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/21 0:51:49阅读更多 →
Windows+macOS 通用 OpenClaw 部署流程,内置依赖一键启动智能桌面助手

Windows+macOS 通用 OpenClaw 部署流程,内置依赖一键启动智能桌面助手

📌教程适配:OpenClaw v2.7.9 | 兼容 Windows10/11、macOS 双系统 📖前言 当下各类本地 AI 工具层出不穷,多数产品仅能完成文字问答交互,很难直接操控电脑执行实际操作。OpenClaw,业内常称小龙虾 AI&#…

2026/7/21 0:01:46阅读更多 →
Codex 接入后 Bug 反增?复盘从个人演示到团队协作的“流程陷阱”

Codex 接入后 Bug 反增?复盘从个人演示到团队协作的“流程陷阱”

聊《一次Codex项目复盘,问题最后出在流程而不是模型》之前,先说一句实在的:别急着背概念,先看它在真实项目里到底解决什么问题。摘要先把这篇文章的目标说清楚:看完之后,你应该能判断这件事值不值得做&…

2026/7/21 0:01:46阅读更多 →
手把手搓一个五子棋游戏,零代码也能当“游戏开发者”

手把手搓一个五子棋游戏,零代码也能当“游戏开发者”

大家好,还是我。前几期带大家做了心情日记本和可视化大屏,后台有朋友留言:“能不能教点好玩的?我想做游戏,但一行代码都不会。”行,这期就安排。今天的目标:从零做一个五子棋游戏。 带AI对战、三…

2026/7/21 0:03:46阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/20 22:51:39阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/20 18:51:18阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/20 18:51:18阅读更多 →