C++新特性 协程

本篇文章我们来讲述一下C++协程

协程(Coroutine)是一种能够挂起个恢复的函数过程  是一种轻量级的并发编程方式,也称为用户级线程。它与传统的线程(Thread)相比,具有更低的开销和更高的执行效率。 协程通常运用在异步调用中。

同步和异步 (拓展):同步是指线程要同时执行 如果没有两者没有同步 则需要线程A 等待线程B 或者主线程等待子线程  而异步编程就不需要线程的等待 但是也要注意线程争夺的问题 

协程要讲清楚非常的抽象和复杂 我们直接从实际入手

代码实例:

大家看完以上代码结果可能会有一点懵 这是什么? 这是怎么回事?下面 让我们来分析一下代码:

大家观察这段代码就知道 main函数创建了一个进程 进程里面创建了一个主线程  然后执行每个函数就是子线程  先进入bar()函数  先执行call bar 然后执行before bar 经过挂起点然后挂起  这时候一个线程跳出了bar函数 到main里面 另一个线程执行fool函数  fool函数执行完以后 再回到bar 函数里面继续执行 这就是本代码的大概思路

下面我们来介绍一下   co_return 和co_await

co_return :co_return 是 C++20 中引入的关键字,用于在协程中返回结果或结束协程。它用于替代 return 关键字,在协程函数中表示返回值,并触发协程的完成。

co_return代码实例:

#include <iostream>
#include <experimental/coroutine>std::experimental::coroutine_handle<> myCoroutine;void myTask() {std::cout << "Starting coroutine..." << std::endl;myCoroutine.resume(); // 启动协程std::cout << "Resuming execution..." << std::endl;
}struct MyAwaitable {bool await_ready() const { return false; }void await_suspend(std::experimental::coroutine_handle<> handle) const {myCoroutine = handle; // 将当前协程保存起来}void await_resume() const {}
};MyAwaitable asyncFunc() {std::cout << "Suspending execution..." << std::endl;co_await MyAwaitable{}; // 挂起协程,等待恢复std::cout << "Resumed execution..." << std::endl;
}int main() {myTask();asyncFunc().await_resume();return 0;
}

在这个示例中,co_await 表达式会挂起 asyncFunc() 协程的执行,然后将控制权交还给 myTask() 协程。当我们调用 myCoroutine.resume() 时,asyncFunc() 的执行恢复,并继续执行后面的语句。

co_await介绍:

co_await 是 C++20 中引入的关键字,用于在协程中挂起当前的执行,并等待某个操作完成或者恢复执行。它是协程内部使用的一种语法,用于表示异步操作的等待。

在一个可暂停函数(协程)中,当遇到 co_await 表达式时,会发生以下几个步骤:

  1. 暂停当前协程的执行,并保存当前状态。
  2. 将控制权返回给调用方(如上层协程或者普通函数)。
  3. 在某个事件发生或者异步操作完成后,恢复之前保存的状态并继续执行。

具体来说,在使用 co_await 时需要满足两个条件:

  1. 表达式必须是一个可暂停的类型(也称为 Awaitable 类型),它要么定义了 bool await_ready() 方法来判断是否可以直接返回结果,要么定义了 void await_suspend(std::coroutine_handle<>) 方法和 void await_resume() 方法来进行挂起和恢复操作。
  2. 协程函数本身必须是异步上下文(比如异步任务、生成器)或者包含了异步操作。

代码实例:

#include <iostream>
#include <experimental/coroutine>struct MyAwaitable {bool await_ready() const { return false; }void await_suspend(std::experimental::coroutine_handle<> handle) const {std::cout << "Suspending coroutine..." << std::endl;handle.resume(); // 恢复协程的执行}void await_resume() const {}
};std::experimental::suspend_always asyncFunc() {std::cout << "Starting coroutine..." << std::endl;co_await MyAwaitable{}; // 使用 co_await 挂起协程std::cout << "Resuming execution..." << std::endl;
}int main() {auto coro = asyncFunc();coro.resume(); // 启动协程return 0;
}

代码总结:在这个示例中,MyAwaitable 是一个自定义的可暂停类型,它定义了 bool await_ready() 方法void await_suspend(std::coroutine_handle<>) 方法来控制协程的挂起和恢复。当我们调用 co_await MyAwaitable{} 时,协程会被挂起,并且打印出相应的消息。然后通过 handle.resume() 来恢复协程的执行。

co_await实现对象:

co_await 来实现协程等待一个对象时,该对象需要满足特定的条件和接口。在 C++ 中,需要实现以下几个关键的部分:

  1. 实现 awaitable 类型:这是一个自定义的类型,表示可以被协程等待的对象。它需要定义 await_ready()await_suspend()await_resume() 这三个成员函数。

    • await_ready(): 返回一个 bool 值,表示对象是否已经准备好(即不需要暂停协程)。如果对象已经可用,则返回 true;否则返回 false。
    • await_suspend(): 返回一个指定异步操作完成后应该如何恢复协程执行的 awaiter 类型。
    • await_resume(): 返回异步操作结果的值。

代码实例:

#include <iostream>
#include <future>
#include <experimental/coroutine>struct Awaitable {std::future<int> fut;bool await_ready() {return fut.wait_for(std::chrono::seconds(0)) == std::future_status::ready;}void await_suspend(std::experimental::coroutine_handle<> handle) {fut.then([handle](std::future<int> f) mutable {// 异步操作完成后恢复协程执行handle.resume();});}int await_resume() {return fut.get();}
};Awaitable makeAsyncRequest() {std::promise<int> p;auto fut = p.get_future();// 模拟异步操作std::thread([&p]() mutable {std::this_thread::sleep_for(std::chrono::seconds(2));p.set_value(42);}).detach();return Awaitable{std::move(fut)};
}std::experimental::suspend_always task() {auto result = co_await makeAsyncRequest(); // 等待异步操作完成,并获取结果std::cout << "Result: " << result << std::endl;
}int main() {auto coro = task();coro.resume(); // 启动协程return 0;
}

总结:协程是应用于异步编程的一种方法 co_await函数用于当前的协程的挂起 这样可以更深层次的满足异步编程 要注意co_await函数的使用 co_return是用来返回结果和结束协程

好了 本篇内容就到这里 这篇文章可能有些难度 大家慢慢理解 

在这里小编想向大家推荐一个课程:https://xxetb.xetslk.com/s/2PjJ3T

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/447732.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

通过Netbackup恢复Oracle备份实操手册

1、系统环境描述 1 2、恢复前数据备份 2 2.1 在NBU上执行一次完整的备份 2 2.2 查看ORACLE的备份集 3 2.2.1在备份客户端上查看备份集 3 2.2.2在备份服务器netbackup上查看客户端备份集 4 3、本机恢复方法 5 3.1丢失SPFILE文件恢复方法 5 3.2丢失CONTROLFILE文件恢复方…

【机器学习】AAAI 会议论文聚类分析

实验五&#xff1a;AAAI 会议论文聚类分析 ​ 本次实验以AAAI 2014会议论文数据为基础&#xff0c;要求实现或调用无监督聚类算法&#xff0c;了解聚类方法。 1 任务介绍 ​ 每年国际上召开的大大小小学术会议不计其数&#xff0c;发表了非常多的论文。在计算机领域的一些大…

“IT行业的黄金证书:你必须了解的顶级认证“

文章目录 每日一句正能量前言一、网络方向&#xff1a;思科认证/软考二、华为认证三、系统方向&#xff1a;红帽认证四、数据库方向&#xff1a;Oracle认证五、信息安全方向&#xff1a;CISP/CISSP认证六、管理方向&#xff1a;PMP认证IT行业证书的价值和作用后记 每日一句正能…

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之TextPicker组件

鸿蒙&#xff08;HarmonyOS&#xff09;项目方舟框架&#xff08;ArkUI&#xff09;之TextPicker组件 一、操作环境 操作系统: Windows 10 专业版、IDE:DevEco Studio 3.1、SDK:HarmonyOS 3.1 二、TextPicker组件 TextClock组件通过文本将当前系统时间显示在设备上。支持不…

ES6中新增Array.from()函数的用法详解

目录 Map对象的转换 Set对象的转换 字符串的转换 类数组对象的转换 Array.from可以接受三个参数 ES6为Array增加了from函数用来将其他对象转换成数组。当然&#xff0c;其他对象也是有要求&#xff0c;也不是所有的&#xff0c;可以将两种对象转换成数组。 1、部署了Iter…

Tauri:相比Electron,还有很长路要走的。

一、Tauri是什么 Tauri是一个开源的框架&#xff0c;用于构建跨平台的桌面应用程序。它允许开发者使用Web技术&#xff08;如HTML、CSS和JavaScript&#xff09;来构建高性能的本地应用程序&#xff0c;同时提供了访问底层操作系统功能的能力。 Tauri的设计目标是提供一种简单…

用VScode写Latex

主要内容可以直接导到这里 A Fast Guide on Writing LaTeX with LaTeX Workshop in VS Code - Jia Jia Math 其中关于TexLive安装完成之后的路径设置有一些迷惑&#xff0c;win11下测试是不需要手动去添加的&#xff0c;去系统变量里检查一下就可以了&#xff0c;应该点开path…

matlab GUI配置传递函数和控制系统设计

1、内容简介 略 43-可以交流、咨询、答疑 涉及到传递函数导入、零极点展示等 2、内容说明 略 % --- Executes on button press in operation. function operation_Callback(hObject, eventdata, handles) % hObject handle to operation (see GCBO) % eventdata reser…

Unknown custom element:<xxx>-did you register the component correctly解决方案

如图所示控制台发现了爆红&#xff08;大哭&#xff09;&#xff1a; 报错解释&#xff1a; 当我们看到报错时&#xff0c;我们需要看到一些关键词&#xff0c;比如显眼的“component”和“name”这两个单词&#xff0c; 因此我们就从此处切入&#xff0c;大概与组件有关系。…

聊聊ClickHouse MergeTree引擎的固定/自适应索引粒度

前言 我们在刚开始学习ClickHouse的MergeTree引擎时&#xff0c;就会发现建表语句的末尾总会有SETTINGS index_granularity 8192这句话&#xff08;其实不写也可以&#xff09;&#xff0c;表示索引粒度为8192。在每个data part中&#xff0c;索引粒度参数的含义有二&#xf…

Rust学习之Features

Rust学习之Features 一 什么是 Features二 默认 feature三 简单的features应用示例四 可选(optional)的依赖五 依赖的特性5.1 在依赖表中指定5.2 在features表中指定 六 命令行中特性控制七 特性统一路径八 其它8.1 相互排斥特性8.2 观察启用特性8.3 [Feature resolver version…

操作系统基础:内存管理概述【上】

&#x1f308;个人主页&#xff1a;godspeed_lucip &#x1f525; 系列专栏&#xff1a;OS从基础到进阶 &#x1f3d5;️1 内存管理基础概念&#x1f3e1;1.1 总览&#x1f3e1;1.2 内存管理应有的功能&#x1f3d6;️1.2.1 内存空间的分配和回收&#x1f3d6;️1.2.2 从逻辑上…