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

C++进阶:coroutine 协程

1. 总述 

协程的本质是一个可以暂停和恢复执行的函数,只要函数体出现了【co_await】、【co_yield】、【co_return】这三个关键字之一,则这个函数将自动变成协程。

而C++20引入的协程是一个无栈协程,其内存分配(协程帧)时机是在协程首次挂起时,注意不是函数调用时,内存默认在堆上分配,是否需要手动释放,依赖于co_return的返回值,详细内容会在下章节介绍。协程帧一般包括如下内容:

┌─────────────────┐
│  协程帧头部     │ ← 编译器内部信息
├─────────────────┤
│  promise对象    │
├─────────────────┤
│  参数副本       │ ← 函数参数按值/引用存储
├─────────────────┤
│  局部变量       │ ← 跨挂起点的局部变量
├─────────────────┤
│  挂起点信息     │ ← 恢复位置、寄存器保存等
├─────────────────┤
│  激活记录       │ ← 嵌套调用信息(如适用)
└─────────────────┘

C++中对协程函数的返回值类型做了限制,返回值类型必须要包含一个名称为【promise_type】的内嵌类型,其主要用于控制协程的行为。

相对于线程,C++协程的优势有很多,主要包括:

  1. 用同步风格写异步代码,代码可读性更好
  2. 协程创建更快,内存占用更低(不涉及栈空间分配),而且因为仅仅是用户层的调度,避免了线程上下文切换开销,性能也更优

2. 协程关键字/函数说明

C++协程中用到了多种关键字,这里面先做一个简单介绍,后续结合代码再做进一步理解:

1. co_await

该关键字的作用是将协程函数异步挂起,等待条件满足后再继续执行,语法为:

auto result = co_await expr; //expr必须为Awaitable类型对象

Awaitable类型至少要包含如下三个成员函数,以便于协程自动化调用,co_wait关键字执行时,会立刻调用await_ready()函数,并根据其结果,进一步确认是否需要调用await_suspend().

当通过协程句柄(std::coroutine_handle<>)调用其resume()函数时,Awaitable类的await_resume()将被调用。

struct MyAwaitable {// 1. 检查是否需要挂起,// true:无需挂起,同普通函数,false:自动调用await_suspend函数bool await_ready();// 2. 挂起时的处理逻辑void await_suspend(std::coroutine_handle<> handle);// 3. 恢复时获取结果auto await_resume();
};

2. co_yield

co_yield 是 C++ 协程中用于生成值序列并挂起协程的关键字。它将协程转变为生成器(Generator),能够按需产生值序列,在每次产生值后自动挂起,等待下一次请求。且若要使用该关键字,则pomise_type类中必须包含yield_value函数的实现。

使用语法为:

// promise_type函数必须实现yield_value()
co_yield expr;

3. co_return

co_return是 C++ 协程中用于结束协程执行并返回最终结果的关键字。它标志着协程的完成,负责清理资源、设置返回值,并将协程置于最终状态。

co_return关键字执行时,会自动化调用promise_type类型中的return_value()或return_void()函数,以获取最终的结果。并在其执行完毕后,自动化执行promise_type对象的final_suspend()函数。

常见语法为:

// 返回一个值
co_return expression;// 无返回值(void 协程)
co_return;

4. std::suspend_never 

主要用于修饰如下三个函数,表征该函数执行完成后无需挂起,要立刻继续执行:

  • initial_suspend():协程立即开始执行,不初始挂起
  • final_suspend():协程完成后自动销毁
  • yield_value():co_yield 后不挂起,继续执行

5. std::suspend_always

std::suspend_always 是一个总是挂起的 Awaitable 类型,它告诉协程必须挂起,等待后续恢复

  • initial_suspend():协程创建后立即挂起,等待手动恢复
  • final_suspend():协程完成后保持挂起,内存需要手动清理
  • yield_value():co_yield 后挂起,等待下一次请求

3. 示例代码及流程解析

下面将结合代码介绍下,协程的整体流程,代码如下:

class IntReader {
public:bool await_ready() {return false;}void await_suspend (std::coroutine_handle<> h) {std::thread([this, h]() {sleep(1000);value_ = 1;h.resume();})thread.detach();}await_resume() {return value_;}
private:int value_{0};
};class Task {class pomise_type{public:pomise_type() : value_(std::make_shared<int>()){}Task get_return_object() {return Task{std::coroutine_handle<promise_type>::from_promise(*this),value_};}void return_value (int value) {*value_ = value;}std::suspend_never initial_suspend() {  return {};}std::suspend_never final_suspend() noexcept { return {}; }void unhandled_exception(){}private:std::shared_ptr<int> value_;};  
public:Task(std::coroutine_handle<promise_type> handle,const std::shared_ptr<int> & value) : handle_(handle),value_(value) {}int GetValue() const {return *value;}
private:std::shared_ptr<int> value_;std::coroutine_handle<promise_type> handle_;
};Task GetInt() {IntReader reader1;int total = co_wait reader1;IntReader reader2;total += co_wait reader2;IntReader reader3;total += co_wait reader3;co_return total;
}int main() {auto task = GetInt();std::cout << task.GetValue() << std::endl;return 0;
}

首先,这里需要强调的是,在调用协程函数时,函数的返回值,即Task对象是有系统自动化调用promise_type对象的get_return_object()函数自动生成的,而非我们主动声明的,这和我们之前的使用方式,差异很大。

http://www.dtcms.com/a/615150.html

相关文章:

  • 网站开发学什么数据库上海seo课程
  • 网站销售的优势crm客户关系管理系统源码
  • Blender:法线图黑白图
  • 做网站要不要钱济南网站优化公司哪家好
  • 编译动态库时只需要知道函数的声明,与可执行文件不同
  • 【OpenGL】CMake报错解决:Error in configuration process,project files may be invalid.
  • AI有利也有坏
  • 网站 备案规定付费推广
  • 慈溪网站开发厦门最新通告
  • GAMES101-现代计算机图形学入门(六)——Cameras、Lenses、Light Fields、Color and Perception
  • OpenAI Assistant API详解
  • 网站建设费用选网络专业wordpress 自定义登陆页面
  • Matplotlib 绘制多图
  • js获取网站广告点击量怎么做在百度怎么免费发布广告
  • 做网站怎么选空间国内知名设计网站
  • 惠州app网站建设排行榜搜索量最高的网站
  • 【STM32】SPI通讯协议入门解析
  • 网站开发邮件服务器版式设计
  • 做维修家具广告在哪个网站好线上营销策略都有哪些
  • 《DevC++支持C++11等与其软件分辨率低的解决办法》
  • YOLO数据集标签数量统计脚本
  • 设计手机网站公司网站游戏网站怎么建设
  • 网站跳出率计算网站开发技术服务费
  • 【概念科普】ACT技术全景解析:跨领域定义与核心价值
  • AUTOSAR_CP_OS-Protection Error Handling:保护错误处理
  • 网站信息内容建设实施办法西安的网站制作公司
  • ollydbg快捷键
  • 企业网站推广方案相册制作模板
  • 石家庄科技中心网站注册完域名 如何做网站
  • 正保建设教育网站网站空间每年继费到哪交