c++20协程详解(四)

news2024/11/28 4:29:55

前言

到这就是协程的最后一节了。希望能帮到大家

代码

到这里我们整合下之前二、三节的代码


#include <coroutine>
#include <functional>
#include <chrono>
#include <iostream>
#include <thread>
#include <mutex>
#include <memory>
#include <vector>

struct async_task_base
{
   virtual void completed() = 0;
   virtual void resume() = 0;
};


std::mutex m;
std::vector<std::shared_ptr<async_task_base>> g_event_loop_queue; 
std::vector<std::shared_ptr<async_task_base>> g_resume_queue; //多线程异步任务完成后后,待主线程恢复的线程
std::vector<std::shared_ptr<async_task_base>> g_work_queue; //执行耗时操作线程队列

enum class EnumAwaiterType:uint32_t{
   EnumInitial = 1, //协程initial
   EnumSchduling = 2,// 用户co_await
   EnumFinal = 3//销毁
};


template <typename ReturnType>
struct CoroutineTask;

template <typename CoTask, EnumAwaiterType AwaiterType >
struct CommonAwaiter ;

template <typename>
struct AsyncAwaiter;


template <typename ReturnType>
struct  AsyncThread
{
   using return_type = ReturnType;

   AsyncThread(std::function<return_type ()>&& func): func_(func){

   }
   std::function<return_type ()> func_;
};


template <typename ReturnType>
struct async_task: public async_task_base{
   async_task(AsyncAwaiter<ReturnType> &awaiter)
   :owner_(awaiter)
   {

   }

   void completed() override{
       ReturnType result = owner_.func_();
       owner_.value_ = result;
   }

   void resume() override{
       owner_.h_.resume();
   }
   AsyncAwaiter<ReturnType> &owner_ ;
};


template <typename ReturnType>
struct AsyncAwaiter
{
   using return_type = ReturnType;

   AsyncAwaiter(AsyncThread<ReturnType>& info){
       // std::cout<< " AsyncAwaiter(AsyncThread<ReturnType>& info)" << std::endl;
       value_ = return_type{};
       func_ = info.func_;
   }

   bool await_ready() const noexcept { 
       return false; 
   }
   
   void await_suspend(std::coroutine_handle<> h)  {
       h_ = h;
       std::lock_guard<std::mutex> g(m);
       g_work_queue.emplace_back(std::shared_ptr<async_task_base>( new async_task<uint64_t>(*this)));
   }

   return_type await_resume() const noexcept { 
       return value_;
   }

 
   std::function<return_type ()> func_;
   std::coroutine_handle<> h_; 
   return_type value_ = return_type();
};


template <typename CoTask, EnumAwaiterType AwaiterType>
struct coroutine_task: public async_task_base{
   coroutine_task(CommonAwaiter<CoTask, AwaiterType> &awaiter)
   :owner_(awaiter)
   {

   }

   void completed() override{
   }

   void resume() override{
       if(owner_.h_.done()){
           owner_.h_.destroy();
       }else{
           owner_.h_.resume();
       }
   }
   CommonAwaiter<CoTask,AwaiterType> &owner_ ;
};

template <typename CoTask, EnumAwaiterType AwaiterType = EnumAwaiterType::EnumSchduling>
struct CommonAwaiter 
{
   using return_type =  typename CoTask::return_type;
   using promise_type = typename CoTask::promise_type;
   CommonAwaiter(promise_type* promise):promise_(promise){
   }

   bool await_ready() const noexcept { 
       return false;
   }

   //也可以直接恢复 
   // std::coroutine_handle<> await_suspend(std::coroutine_handle<> h)  {
   //     return h;
   // }

   void await_suspend(std::coroutine_handle<> h)  {
       h_ = h;
       g_event_loop_queue.emplace_back(std::shared_ptr<async_task_base>( new coroutine_task<CoTask, AwaiterType>(*this)) );
   }


   return_type await_resume() const noexcept { 
       return promise_->get_value();
   }

   ~CommonAwaiter(){
   }

   bool resume_ready_= false;
   promise_type* promise_ = nullptr;
   std::coroutine_handle<> h_ = nullptr;
};


template <typename CoTask>
struct CommonAwaiter<CoTask, EnumAwaiterType::EnumInitial>
{
   CommonAwaiter(){
   }

   bool await_ready() const noexcept { 
       return true;
   }

   void await_suspend(std::coroutine_handle<>)  {
   }

   void await_resume() const noexcept { 
   }

   ~CommonAwaiter(){
   }
};



template <typename CoTask>
struct CommonAwaiter <CoTask, EnumAwaiterType::EnumFinal>
{
   CommonAwaiter(){
   }

   bool await_ready() noexcept { 
       return false;
   }

   void await_suspend(std::coroutine_handle<> h)  noexcept{
       h_ = h;
       g_event_loop_queue.emplace_back(std::shared_ptr<async_task_base>( new coroutine_task<CoTask, EnumAwaiterType::EnumFinal>(*this)));
   }

   void await_resume()  noexcept{ 
   }

   std::coroutine_handle<> h_ = nullptr;
};


template<typename CoTask>
struct Promise
{
   using return_type  = typename CoTask::return_type ;
   ~Promise(){
   }
   CommonAwaiter<CoTask, EnumAwaiterType::EnumInitial> initial_suspend() {
       return {}; 
   };
   
   CommonAwaiter<CoTask, EnumAwaiterType::EnumFinal> final_suspend() noexcept { 
       return {}; 
   }

   void unhandled_exception(){
       std::rethrow_exception(std::current_exception());
   }

   CoTask get_return_object(){ 
       return  CoTask(this);
   }

   return_type get_value() {
       return value_;
   }


   void return_value(return_type value){
       value_ = value;
   }
  
   template<typename T>
   CommonAwaiter<CoroutineTask<T>> await_transform(CoroutineTask<T> &&task){
       return CommonAwaiter<CoroutineTask<T>>(task.p_);
   }

 
   template<typename T>
   inline AsyncAwaiter<T> await_transform(AsyncThread<T>&& info)
   {
       return AsyncAwaiter(info);
   }



   return_type value_;
};

template <typename ReturnType>
struct CoroutineTask{

   using return_type  = ReturnType;
   using promise_type = Promise<CoroutineTask>;

   CoroutineTask(const CoroutineTask &other) = delete;
   CoroutineTask(const CoroutineTask &&other) = delete;
   CoroutineTask& operator=(const CoroutineTask&) {};
   CoroutineTask& operator=(const CoroutineTask&&) = delete;

   CoroutineTask(promise_type* promise) {
       p_ = promise;
       
   }

   promise_type *p_ = nullptr;

};


void do_work() {
   while (1)
   {
       std::lock_guard<std::mutex> g(m);
       for(auto task : g_work_queue){
           task->completed();
           g_resume_queue.push_back(task);
       }
       
       g_work_queue.clear();
   }   
   
}

void run_event_loop(){
   std::vector<std::shared_ptr<async_task_base>> g_raw_work_queue_tmp;
   std::vector<std::shared_ptr<async_task_base>> g_event_loop_queue_temp;
   while(1){
       g_raw_work_queue_tmp.clear();
       g_event_loop_queue_temp.clear();
       {
           g_event_loop_queue_temp.swap(g_event_loop_queue);
           std::lock_guard<std::mutex> g(m);
           g_raw_work_queue_tmp.swap(g_resume_queue);
       }
       
       for(auto &task : g_raw_work_queue_tmp){
           task->resume();
       }

       for(auto task : g_event_loop_queue_temp){
           task->resume();
       }

   }
}


// ------------------------------------------------------------------------------------------------------



template <typename ReturnType>
AsyncThread<ReturnType> do_slow_work(std::function< ReturnType () > &&func){
   return AsyncThread<ReturnType>(std::forward< std::function< ReturnType () > >(func));
}


CoroutineTask<u_int64_t> second_coroutine(){
   co_return 3;
}

CoroutineTask<float> third_coroutine(){
   co_return 3.1;
}


CoroutineTask<char> first_coroutine(){
   int a = 1;
   auto func =[&]() -> uint64_t{
       // std::cout<< "do a slow work !!!!!!!!!!!!!!!!!!!!!" << std::endl;
       return a;
   };  
   uint64_t result = co_await do_slow_work<uint64_t>(func);
   std::cout << "@@@@@@@@@ result1 is  : " << result  << std::endl;  
   a = 2;
   result = co_await do_slow_work<uint64_t>(func);
   std::cout << "@@@@@@@@@ result2 is  : " << result  << std::endl; 
   uint64_t num =  co_await second_coroutine();
   std::cout << "@@@@@@@@@ second_coroutine result is  : " << num  << std::endl; 
   a = 3;
   result = co_await do_slow_work<uint64_t>(func);
   std::cout << "@@@@@@@@@ result3 is  : " << result  << std::endl;  
   float num2 =  co_await third_coroutine();
   a = 4;
   result = co_await do_slow_work<uint64_t>(func);
   std::cout << "@@@@@@@@@ third_coroutine result is  : " << num2  << std::endl; 
   result = co_await do_slow_work<uint64_t>(func);
   std::cout << "@@@@@@@@@ result4 is  : " << result  << std::endl;  
   co_return 'b';
}


CoroutineTask<char> Coroutine(){
   int a = 1;
   auto func =[&]() -> uint64_t{
       // std::cout<< "do a slow work !!!!!!!!!!!!!!!!!!!!!" << std::endl;
       return a;
   };  
   uint64_t result = co_await do_slow_work<uint64_t>(func);
   std::cout << "@@@@@@@@@ result is  : " << result  << std::endl; 
   uint64_t num =  co_await second_coroutine();
   std::cout << "@@@@@@@@@ coroutine result is  : " << num  << std::endl; 

   co_return 'b';
}


void test_func(){
   Coroutine();
   first_coroutine();
}

int main(){
   test_func();
   std::thread work_thread(do_work);
   run_event_loop();
   return 0;
}

分析

将对两种awaiter的co_await操作规则定义到promise中
在这里插入图片描述
对co_await可以使用await_transform 和重载co_await运算符,但是两种用法不能同时存在。

在这里插入图片描述
优先恢复其他线程完成耗时任务的协程,再进行当前线程中的协程挂起、销毁、恢复调度。

协程函数相对对于协程的优势

协程每次都会在final_suspend和initial_suspend时创建awaiter,以及对awaiter挂起,在for循环中,这样显然不科学,但异步函数只有一个awaiter,在for循环中更合适。

运行结果

在这里插入图片描述

待扩展

异步io

如果对使用epoll实现网络io异步函数感兴趣,可以自行实现,实现方式和实现多线程异步函数一样,这里就不实现了,注意下epoll中,不能添加普通文件系统fd。

协程超时机制

可以加上定时器对async_task_base进行超时检查,以此来支持协程超时

流程图

最后附上co_await Coroutine()的流程图

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

政安晨【AIGC实践】(一):在Kaggle上部署使用Stable Diffusion

目录 简述 开始 配置 执行 安装完毕&#xff0c;一键运行 结果展示 政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: 人工智能数字虚拟世界实践 希望政安晨的博客能够对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提…

spring加载类初始化顺序

今天看spring官网的时候&#xff0c;提到了Ordered执行顺序。我当时记得PostConstruct注解会在bean加载后执行&#xff0c;现在又来了一个执行顺序&#xff0c;直接给我整蒙了。 于是我写了一个简单的dom来看看&#xff0c;它是什么&#xff1a; Service("t2ServerImpl&q…

Vue - 你知道Vue中key的工作原理吗

难度级别:中级及以上 提问概率:80% 在Vue项目开发中,并不推荐使用索引做为key,以为key必须是唯一的,可以使用服务端下发的唯一ID值,也不推荐使用随机值做为key,因为如果每次渲染都监听到不一样的key,那么节点将无法复用,这与Vue节省…

中药提取物备案数据库<5000+中药提取物>

NMPA中药提取物备案数据库的建立是确保中药提取物质量安全、规范生产行为、加强监管、保障公众用药安全、促进产业发展和国际化的重要措施。 通过查询中药提取物备案信息我们能了解到中药提取物的实用备案号、药品通用名称、药品生产企业、批准文号、备案日期、备案状态、中药…

分表?分库?分库分表?实践详谈 ShardingSphere-JDBC

如果有不是很了解ShardingSphere的可以先看一下这个文章&#xff1a; 《ShardingSphere JDBC?Sharding JDBC&#xff1f;》基本小白脱坑问题 阿丹&#xff1a; 在很多开发场景下面&#xff0c;很多的技术难题都是出自于&#xff0c;大数据量级或者并发的场景下面的。这里就出…

【LeetCode刷题记录】11. 盛最多水的容器

11 盛最多水的容器 给定一个长度为 n 的整数数组 height。有 n 条垂线&#xff0c;第 i 条线的两个端点是 ( i , 0 ) (i, 0) (i,0)和 ( i , h e i g h t [ i ] ) (i, height[i]) (i,height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最多的…

MySQL学习路线一条龙

引言 在当前的IT行业&#xff0c;无论是校园招聘还是社会招聘&#xff0c;MySQL的重要性不言而喻。 面试过程中&#xff0c;MySQL相关的问题经常出现&#xff0c;这不仅因为它是最流行的关系型数据库之一&#xff0c;而且在日常的软件开发中&#xff0c;MySQL的应用广泛&#…

数字人直播系统是什么?AI数字人直播间搭建方法来了!

无人直播的时代&#xff0c;短视频和直播平台正在风口&#xff0c;各条赛道内也早已人满为患&#xff0c;很多线下商家都想参与其中&#xff0c;因为时间、地方、设备等限制久久不能去实行起来。所以&#xff0c;数字人直播新模式成为了线下商家的救星&#xff0c;线下商家方法…

unity_Button:单击的三种实现方式

此代码直接绑定到button上面无需其他操作 using UnityEngine; using UnityEngine.UI;public class PrintHelloOnButtonClick : MonoBehaviour {private Button button;void Start(){// 获取当前GameObject上的Button组件button GetComponent<Button>();// 添加点击事件…

探索基于WebRTC的有感录屏技术开发流程

title: 探索基于WebRTC的有感录屏技术开发流程 date: 2024/4/7 18:21:56 updated: 2024/4/7 18:21:56 tags: WebRTC录屏技术屏幕捕获有感录屏MediaStream实时传输音频录制 第一章&#xff1a;技术原理 WebRTC&#xff08;Web Real-Time Communication&#xff09;是一种开放源…

什么是FIG图片格式?如何把jpg图片转FIG格式?

一&#xff0c;什么是FIG图片格式 FIG图片格式&#xff0c;全称为Figma Image Format&#xff0c;是一种由Figma设计软件专用的图像格式。Figma是一款强大的在线协作设计工具&#xff0c;广泛应用于UI/UX设计、产品设计和图标设计等领域。 二&#xff0c;FIG图片格式的优点 …

Prometheus服务发现与监控案例-Day 02

1. 服务发现简介 prometheus采用pull方式拉取指定目标实例的监控数据&#xff0c;也就是间隔固定的周期去目标实例上抓取metrics数据&#xff0c;每一个被抓取的目标实例都需要暴露一个数据指标API接口&#xff0c;prometheus通过这个暴露的接口就可以获取到其指标数据. 这种方…

MySQL基础练习题:习题2-3

这部分主要是为了帮助大家回忆回忆MySQL的基本语法&#xff0c;数据库来自于MySQL的官方简化版&#xff0c;题目也是网上非常流行的35题。这些基础习题基本可以涵盖面试中需要现场写SQL的问题。上期帮助大家建立数据库&#xff0c;导入数据&#xff0c;接下来让我们继续练习。 …

51单片机入门_江协科技_17~18_OB记录的笔记

17. 定时器 17.1. 定时器介绍&#xff1a;51单片机的定时器属于单片机的内部资源&#xff0c;其电路的连接和运转均在单片机内部完成&#xff0c;无需占用CPU外围IO接口&#xff1b; 定时器作用&#xff1a; &#xff08;1&#xff09;用于计时系统&#xff0c;可实现软件计时&…

【LeetCode热题100】74. 搜索二维矩阵(二分)

一.题目要求 给你一个满足下述两条属性的 m x n 整数矩阵&#xff1a; 每行中的整数从左到右按非严格递增顺序排列。每行的第一个整数大于前一行的最后一个整数。 给你一个整数 target &#xff0c;如果 target 在矩阵中&#xff0c;返回 true &#xff1b;否则&#xff0c;…

GD32F470_US-016 模拟电压输出 双量程 模拟量 超声波测距模块 高精度

2.18 US-016电压式超声波测距传感器 US-016是市场上唯有的一款模拟量输出的超声波测距模块&#xff0c;输出的模拟电压和距离值成正比&#xff0c;可以方便的和其他系统相连&#xff0c;US-016工作稳定可靠。 US-016超声波测距模块可实现2cm~3m的非接触测距功能&#xff0c;供…

Android 9.0 framework层实现app默认全屏显示

1.前言 在9.0的系统rom产品定制化开发中,在对于第三方app全屏显示的功能需求开发中,需要默认app全屏显示,针对这一个要求,就需要在系统启动app 的过程中,在绘制app阶段就设置全屏属性,接下来就实现这个功能 效果图如下: 2.framework层实现app默认全屏显示的核心类 fram…

红黑树深度解析:RB-DELETE操作的理论与实践

红黑树深度解析&#xff1a;RB-DELETE操作的理论与实践 一、前言二、红黑树的核心性质三、RB-DELETE的过程四、RB-DELETE的实现细节五、RB-DELETE的复杂性分析六、维护红黑树性质的重要性七、代码示例7.1 伪代码7.2 C代码示例 八、结论 一、前言 在现代计算机科学中&#xff0…

备忘,LangChain建立本地知识库的几个要点

本地知识库可以解决本地资源与AI结合的问题&#xff0c;为下一步应用管理已有资产奠定基础。 本地知识库的建立可参考LangChain结合通义千问的自建知识库 &#xff08;二&#xff09;、&#xff08;三&#xff09;、&#xff08;四&#xff09; 本文主要记录两个方面的问题 1 搭…

抖音引流私域转化模式1.0现场视频,从抖音源源不断把人加到私域买单

抖音-引流私域转化模式1.0现场视频&#xff0c;从抖音源源不断把人加到私域&#xff0c;让加到私域的粉丝买单 课程内容&#xff1a;抖音引流私域转化模式1.0现场视频&#xff0c;从抖音源源不断把人加到私域买单 - 百创网-源码交易平台_网站源码_商城源码_小程序源码 01.第一…