发布时间:2026/7/20 17:02:55
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 协程需要一定的学习曲线但一旦理解其核心机制就能编写出简洁、高效且易于维护的异步代码。

相关新闻

C++图形渲染管线:从原理到软渲染实现
2026/7/20 17:02:55

C++图形渲染管线:从原理到软渲染实现

一、C图形渲染管线:从原理到软渲染实现图形渲染管线(Graphics Rendering Pipeline)是现代计算机图形学的核心概念,它描述了将三维场景数据转换为二维屏幕像素的完整流程。无论你使用 OpenGL、DirectX、Vulkan 还是 Metal&#xff…

阅读更多
【小程序计算机毕业设计案例】高校食堂菜品展示与线上点餐系统 校园餐饮数字化点餐运维管理系统 学生便捷订餐与食堂后厨管理系统(程序+文档+讲解+定制)
2026/7/20 17:02:55

【小程序计算机毕业设计案例】高校食堂菜品展示与线上点餐系统 校园餐饮数字化点餐运维管理系统 学生便捷订餐与食堂后厨管理系统(程序+文档+讲解+定制)

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

阅读更多
为什么p5play是初学者学习游戏开发的完美选择?5大优势解析
2026/7/20 16:02:54

为什么p5play是初学者学习游戏开发的完美选择?5大优势解析

为什么p5play是初学者学习游戏开发的完美选择?5大优势解析 【免费下载链接】p5play JavaScript game engine that uses q5.js/p5.js for graphics and Box2D for physics. 项目地址: https://gitcode.com/gh_mirrors/p5/p5play p5play是一款基于p5.js图形库和…

阅读更多
TMS320F2807x输出交叉开关:硬件信号路由与实时控制配置详解
2026/7/21 9:03:05

TMS320F2807x输出交叉开关:硬件信号路由与实时控制配置详解

1. 输出交叉开关(OUTPUT X-BAR)核心概念与设计思路在嵌入式系统,尤其是像TI C2000系列这样的高性能实时微控制器中,外设间的信号路由能力直接决定了系统的灵活性和性能上限。TMS320F2807x的输出交叉开关模块,本质上是一…

阅读更多
一文搞懂 ROS2 C++ 订阅节点类成员
2026/7/21 9:03:05

一文搞懂 ROS2 C++ 订阅节点类成员

目录 前言 摘要 一、完整代码示例:/cmd_vel 订阅节点 二、LimoTopicSub 类本身详解 2.1 class LimoTopicSub : public rclcpp::Node 是什么意思? 2.2 rclcpp::Node 是什么? 2.3 继承后 LimoTopicSub 就能当 ROS2 节点用吗?…

阅读更多
解锁AMD Ryzen隐藏性能:SMUDebugTool免费调试工具终极方案
2026/7/21 9:03:05

解锁AMD Ryzen隐藏性能:SMUDebugTool免费调试工具终极方案

解锁AMD Ryzen隐藏性能:SMUDebugTool免费调试工具终极方案 【免费下载链接】SMUDebugTool A dedicated tool to help write/read various parameters of Ryzen-based systems, such as manual overclock, SMU, PCI, CPUID, MSR and Power Table. 项目地址: https:…

阅读更多
哔咔漫画下载器终极指南:3步打造个人离线漫画库,下载速度提升300%
2026/7/21 9:03:05

哔咔漫画下载器终极指南:3步打造个人离线漫画库,下载速度提升300%

哔咔漫画下载器终极指南:3步打造个人离线漫画库,下载速度提升300% 还在为网络不稳定无法畅快阅读哔咔漫画而烦恼吗?picacomic-downloader 是一款专为哔咔漫画(manhuabika.com)设计的专业级下载工具,通过现…

阅读更多
彻底解决BurpSuite与SqlMapAPI连接超时:端口、防火墙与配置全解析
2026/7/21 9:03:05

彻底解决BurpSuite与SqlMapAPI连接超时:端口、防火墙与配置全解析

1. 项目概述与核心痛点 如果你是一名安全测试人员或渗透测试爱好者,那么“SqlMap BurpSuite”这套组合拳,你肯定不陌生。它堪称是自动化SQL注入测试的“黄金搭档”——在BurpSuite里抓到可疑的HTTP请求,一键发送给SqlMap的API接口进行深度检…

阅读更多
房产租赁数字化落地|SpringBoot+Vue租房管理平台集成星火大模型业务全解
2026/7/21 8:02:57

房产租赁数字化落地|SpringBoot+Vue租房管理平台集成星火大模型业务全解

房产租赁数字化落地|SpringBootVue租房管理平台集成星火大模型业务全解 行业痛点 2026年国内长租公寓、个人房东托管市场规模持续扩张,重庆、杭州等新一线城市线下租房交易仍存在明显痛点:房源审核人工耗时久、租客看不懂制式租房合同、报修…

阅读更多
噗叽短视频界面分析
2026/7/21 1:15:47

噗叽短视频界面分析

1 和小红书类似,可以采用类似判断方法------------其实他比小红书好判断,因为他没有图片,控件位置几乎是固定的,都不用判断------------2 因为他没有点赞按钮------------而且几乎所有控件位置都是完全一样的,所以我就…

阅读更多
噗叽自动化评论脚本基本完成
2026/7/21 1:23:43

噗叽自动化评论脚本基本完成

整个开发过程,耗时2.5小时:

阅读更多
游戏服务器性能调优:基于 ECS 架构的确定性帧同步与 Go 协程并发模型实践
2026/7/21 1:12:56

游戏服务器性能调优:基于 ECS 架构的确定性帧同步与 Go 协程并发模型实践

游戏服务器性能调优:基于 ECS 架构的确定性帧同步与 Go 协程并发模型实践 一、游戏服务器的性能铁三角:帧率、延迟、并发数 游戏服务器与普通 Web 服务器的性能指标完全不同。Web 服务器关注 QPS 和 P99 延迟,游戏服务器关注帧速率&#xff0…

阅读更多
只会用工具不算黑客,手把手教你写第一个渗透脚本
2026/7/21 0:02:56

只会用工具不算黑客,手把手教你写第一个渗透脚本

从“工具人”到“创造者”:为什么只会用工具不算黑客 在网络安全的学习道路上,很多初学者都会经历一个相似的阶段:手里攥着一堆神器,Burp Suite 抓包改包行云流水,SQLMap 一键注入势如破竹,Nmap 扫描全网段…

阅读更多
北京华恒智信破解景区酒店考核形式主义案例
2026/7/21 0:02:56

北京华恒智信破解景区酒店考核形式主义案例

一、国有文旅集团传统服务考核的核心痛点国有文旅集团旗下涵盖酒店、景区、旅行社等多元业务板块,普遍重视员工服务培训,持续投入大量成本优化服务能力,但在服务考核环节长期存在主观性过强的问题,陷入“凭感觉打分”的管理困境。…

阅读更多
北京华恒智信破解文旅集团薪酬天花板改革案例
2026/7/21 0:02:56

北京华恒智信破解文旅集团薪酬天花板改革案例

工资总额是国有文旅企业的薪酬“天花板”,市场竞争是行业发展的“硬道理”。在国企改革深化提升的大背景下,国有文旅企业薪酬改革的核心难题,是在政策红线约束与市场化人才竞争之间探寻可持续发展路径。如何在固定薪酬总额管控下留住核心人才…

阅读更多
基于Dify与DeepSeek构建私有知识库问答系统实战指南
2026/7/20 0:40:52

基于Dify与DeepSeek构建私有知识库问答系统实战指南

在业务中快速构建一个能理解私有文档、准确回答专业问题的智能助手,是很多开发团队面临的共同挑战。传统方案往往需要从零开始搭建复杂的 RAG(检索增强生成)系统,涉及文档解析、向量化、检索、大模型调用等多个环节,整…

阅读更多
FAE放射组学分析工具:医学影像特征探索的完整解决方案
2026/7/20 0:48:14

FAE放射组学分析工具:医学影像特征探索的完整解决方案

FAE放射组学分析工具:医学影像特征探索的完整解决方案 【免费下载链接】FAE FeAture Explorer 项目地址: https://gitcode.com/gh_mirrors/fae/FAE 你是否曾经面对海量医学影像数据感到无从下手?想要从CT、MRI等影像中提取有价值的定量特征&#…

阅读更多
DesktopNaotu:你的终极离线思维导图解决方案,告别网络依赖!
2026/7/20 0:45:44

DesktopNaotu:你的终极离线思维导图解决方案,告别网络依赖!

DesktopNaotu:你的终极离线思维导图解决方案,告别网络依赖! 【免费下载链接】DesktopNaotu 桌面版脑图 (百度脑图离线版,思维导图) 跨平台支持 Windows/Linux/Mac OS. (A cross-platform multilingual Mind Map Tool) 项目地址:…

阅读更多