当前位置: 首页 > news >正文

[C++]C++20协程的原理

文章目录

      • 协程的状态机
      • Promise 对象
      • 挂起和恢复机制
      • 协程的执行流程
      • 示例代码分析

C++ 协程是 C++20 引入的一项重要特性,它提供了一种更简洁、高效的异步编程方式。下面从协程的状态机、Promise 对象、挂起和恢复机制等方面介绍其底层实现原理。

协程的状态机

从底层角度看,协程本质上是一个状态机。在运行过程中,协程会经历多个状态,像初始状态、挂起状态、恢复状态以及完成状态等。编译器会把协程函数转化为一个状态机,这个状态机能够在不同状态之间进行切换。

当协程函数被调用时,它并不会马上执行函数体里的代码,而是创建一个协程帧(Coroutine Frame)。协程帧是一个数据结构,用于保存协程的状态,其中包含局部变量、函数参数以及当前执行的位置等信息。

Promise 对象

Promise 对象在协程的实现中起着关键作用。每个协程都有一个与之关联的 Promise 对象,它负责管理协程的生命周期和结果。Promise 对象定义了协程的一些关键行为,例如协程开始时是否挂起、协程结束时如何处理返回值等。

Promise 对象包含以下几个重要的成员函数:

  • get_return_object:该函数用于创建协程的返回对象,这个返回对象通常是一个包装器,用于控制协程的执行和获取协程的结果。
  • initial_suspend:此函数决定协程在开始执行时是否挂起。如果返回一个挂起状态,协程将在创建后立即挂起,直到被恢复。
  • final_suspend:该函数决定协程在结束时是否挂起。通常用于实现协程的自动销毁或资源清理。
  • return_value:该函数用于处理协程的返回值。当协程使用 co_return 语句返回值时,这个值会被传递给 return_value 函数进行处理。
  • unhandled_exception:此函数用于处理协程中抛出的未处理异常。

挂起和恢复机制

协程的核心特性之一是能够在执行过程中挂起和恢复。在协程函数中,可以使用 co_awaitco_yield 关键字来挂起协程的执行。

  • co_await:当协程遇到 co_await 表达式时,它会调用该表达式的 await_suspend 函数。这个函数决定协程是否挂起,如果返回 true,协程将挂起,控制权会返回给调用者。当异步操作完成后,协程可以通过某种机制被恢复,继续执行 co_await 之后的代码。
  • co_yieldco_yield 用于生成一个值并挂起协程。它实际上是 co_await 的一种特殊形式,会调用 Promise 对象的 yield_value 函数来处理生成的值,并挂起协程。

协程的执行流程

以下是协程的基本执行流程:

  1. 创建协程帧:当协程函数被调用时,编译器会创建一个协程帧,用于保存协程的状态。
  2. 调用 Promise 对象的 get_return_object 函数:创建协程的返回对象。
  3. 调用 Promise 对象的 initial_suspend 函数:决定协程是否在开始时挂起。
  4. 执行协程函数体:如果协程没有在开始时挂起,开始执行协程函数体中的代码。
  5. 遇到 co_awaitco_yield 关键字:调用相应的 await_suspendyield_value 函数,决定协程是否挂起。
  6. 挂起协程:如果 await_suspendyield_value 函数返回 true,协程挂起,控制权返回给调用者。
  7. 恢复协程:当异步操作完成或满足恢复条件时,协程可以被恢复,继续执行 co_awaitco_yield 之后的代码。
  8. 协程结束:当协程执行到 co_return 语句或函数结束时,调用 Promise 对象的 return_value 函数处理返回值,然后调用 final_suspend 函数决定是否在结束时挂起。

示例代码分析

#include <iostream>
#include <coroutine>// 协程返回类型
template<typename T>
struct Task {struct promise_type {T value_;Task get_return_object() { return {}; }std::suspend_never initial_suspend() { return {}; }std::suspend_never final_suspend() noexcept { return {}; }void return_value(T value) { value_ = value; }void unhandled_exception() {}};
};// 协程函数
Task<int> async_function() {co_await std::suspend_always{};co_return 42;
}int main() {auto task = async_function();std::cout << "协程已启动,继续执行其他任务..." << std::endl;// 这里需要更完善的机制来恢复协程和获取结果std::cout << "假设协程已完成,结果应该是: 42" << std::endl;return 0;
}

在这个示例中:

  • Task 是协程的返回类型,它包含一个 promise_type 结构体,定义了协程的关键行为。
  • async_function 是一个协程函数,使用 co_await 关键字挂起协程的执行,然后使用 co_return 语句返回一个值。
  • main 函数中,调用 async_function 启动协程,然后可以继续执行其他任务。

通过这种方式,C++ 协程提供了一种高效、简洁的异步编程方式,使得异步代码可以以同步的方式编写,提高了代码的可读性和可维护性。

相关文章:

  • Java基础 4.29
  • 【18】爬虫神器 Pyppeteer 的使用
  • Mysql存储引擎、锁机制
  • 【深度学习的灵魂】图片布局生成模型LayoutPrompt(1)
  • 算法题(137):丢手绢
  • (003)Excel 在滚动的时候,保持标题栏可见
  • C# 继承详解
  • MCP Java SDK 介绍与使用指南
  • Lucene中不同搜索类型的使用方法、基本概念、应用场景、差异对比,并通过表格进行总结
  • Linux系统基础:基础指令简介(网络概念部分)
  • 价值投资笔记:企业护城河——虚假陷阱与隐性壁垒的深度解析
  • Arduion 第一天,变量的详细解析
  • 数据结构|并查集
  • 一些常用的深度学习可视化平台:TensorBoard、Weights Biases (wandb)、VisualDL
  • 【11408学习记录】考研英语语法核心:倒装句考点全解+真题演练
  • 双剑合璧:融合视觉基础与语言模型,勇闯未知领域的语义分割新框架
  • Unity Audio DSP应用与实现
  • java练习3
  • 内网穿透:Cloudflare连接没有公网电脑的RDP/SMB/SSH-(亲测)
  • 宿主机与虚拟机的通讯以及上网问题解决
  • 英欧再“牵手”,友好“靠美国”
  • 长三角哪些城市爱花钱?这个城市令人意外
  • 讲述“外国货币上的中国故事”,《世界钱币上的中国印记》主题书刊出版发布
  • 人民日报:不能层层加码,要层层负责
  • 韦尔股份拟更名豪威集团:更全面体现公司产业布局,准确反映未来战略发展方向
  • 述评:赖清德当局上台一年恶行累累