C++20 协程体验

news2024/11/25 11:50:31

1 介绍

  • 协程是比线程更加轻量级并发编程方式,CPU资源在用户态进行切换,CPU切换信息在用户态保存。

  • 协程完成异步的调用流程,并对用户展示出同步的使用方式。

  • 协程的调度由应用层决定,所以不同的实现会有不同的调度方式,调度策略比较灵活。

  • 协程是基于线程之上运行,同一个线程中,协程是串行的,不会产生线程资源的竞争,不同的协程间却是相互交叉运行的,只要依赖的线程没有终止,协程最终会跳转回来。

  • 协程可以充分利用单核CPU的资源,但是不太好利用多核CPU资源。

  • c++20 协程使用三大关键字 co_wait,co_return,co_yield

  • 在函数中使用到以上关键字的函数被称为协程函数,并且通过该关键字完成跳转。

2 使用

如果要使用协程函数,需要定义promise_type以及基本成员函数实现。

包括get_return_object、initial_suspend、final_suspend、unhandled_exception。

演示代码最下面展示

co_return 执行完协程函数并返回结果

需要额外定义return_void函数。

流程分析:

1 可以看出调用co_return跳转到return_void,return_void执行完后,main函数向下执行。

2 "co_test1 end"并没有打印,说明协程函数co_test1分割开来,通过co_return切换了CPU资源,使主线程继续执行。

co_await 执行到异步操作处,判断并进行挂起操作。

使用co_await 还需要再定义xxxx类并实现await_ready、await_suspend、await_resume函数。

1 协程函数中调用co_await后,跳转xxx的await_ready并判断是否就绪,如果是true,则协程函数调回继续运行,反之进入await_suspend挂起,协程函数跳出,直到调用await_resume后再次跳入协程函数执行余下操作。

2 可以看到在“co_test2 result”打印之前,main函数已执行完成,等到await_resume后依然会跳回协程函数并执行余下部分。

co_yield 让出操作

需要额外定义yield_value函数。

1 执行co_yield 会跳转到yield_value函数中,通过resume以及promise操作获取结果。

3 代码用例

以下代码在linux下测试,gcc版本需要 linux-gcc10.1以上。

编译指令:g++ faw.cpp -fcoroutines -std=c++20

#include <iostream>
#include <coroutine>
#include <thread>
#include <functional>
#include <chrono>

template <typename... Args>
void print_log(const char* fmt, Args... args) {
    char log_buf[128] = { 0 };
    snprintf(log_buf, 128, fmt, args...);
    char time_buf[64] = { 0 };
    unsigned long tid = pthread_self();
    char buf[160] = { 0 };
    snprintf(buf, 160, "[%lu] [%s]", tid, log_buf);
    std::cout << buf << std::endl;
}

using callback_t = std::function<void(int)>;
void async_op(int value, callback_t cb) {
      std::thread t([value, cb]() {
            std::this_thread::sleep_for(std::chrono::milliseconds(1000));
            cb(value+1000);
      });
      t.detach();
}

struct MyTask {
      struct promise_type;
      using handle_t = std::coroutine_handle<promise_type>;  //yield操作
      MyTask() {
      }
      MyTask(handle_t handle)
            : handle_(handle) {
      }
      struct promise_type {
            MyTask get_return_object() {
                  print_log("get_return_object beg");
                  return MyTask(handle_t::from_promise(*this));
            }
            std::suspend_never initial_suspend() {
                  print_log("initial_suspend beg");
                  return std::suspend_never();
            }
            std::suspend_never final_suspend() noexcept {
                  print_log("final_suspend beg");
                  return std::suspend_never();
            }

            //co_return
            void return_void() {
                  print_log("return_void beg");
                  std::this_thread::sleep_for(std::chrono::milliseconds(1000)); //测试异步
            }
            void unhandled_exception() {}

            //co_yield
            auto yield_value(int v) {
                  data_ = v;
                  return std::suspend_always();
            }

            int data_ = 0;
      };

 int get_value() {
       handle_.resume();
       if(!handle_.done()){
            return handle_.promise().data_;
       }
       return -1;
 }

      handle_t handle_;
};

//co_await操作
class AwaitOp {
public:
      AwaitOp(int value)
            : input_(value), result_(0) {}

      bool await_ready() {
            print_log("await_ready beg");
            std::this_thread::sleep_for(std::chrono::milliseconds(1000));  //测试阻塞情况
            return false;
      }

      void await_suspend(std::coroutine_handle<> handle) {
            auto cb = [handle, this](int value) mutable {
                  result_ = value;
                  print_log("----------");
                  handle.resume();   //执行完后调回
                  
            };
            async_op(input_, cb);
      }

      int await_resume() {
            print_log("await_resume beg");
            return result_;
      }
private:
      int input_;;
      int result_;
};

#if 1
MyTask co_test1(){
    print_log("co_test1 beg");
    co_return;   //业务跳转,协程函数退出
    print_log("co_test1 end");
}

MyTask co_test2(){
    print_log("co_test2 beg");
    int input= 999;
    int result = co_await AwaitOp(input);   //业务跳转,协程函数退出
    print_log("co_test2 result=%d",result);
    co_return;
    print_log("co_test2 end");
}

#endif
MyTask co_test3_2(){
    print_log("co_test3_2 beg");
    int t = 99;
    co_yield t;  //切换出去
    print_log("co_test3_2 end");
}

void co_test3(){
      MyTask task = co_test3_2();
      int result = task.get_value();  //切换结果
      print_log("co_test3 result=%d",result);
}

int main() {
      print_log("main beg");

      co_test1();     //co_return测试
      //co_test2();   //co_await测试
      //co_test3();   //co_yield测试
      print_log("main end");
      getchar();
      return 0;
}

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

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

相关文章

麻雀算法SSA优化LSTM长短期记忆网络实现分类算法

1、摘要 本文主要讲解&#xff1a;麻雀算法SSA优化LSTM长短期记忆网络实现分类算法 主要思路&#xff1a; 准备一份分类数据&#xff0c;数据介绍在第二章准备好麻雀算法SSA&#xff0c;要用随机数据跑起来用lstm把分类数据跑起来将lstm的超参数交给SSA去优化优化完的最优参数…

Python可变对象与不可变对象的浅拷贝与深拷贝

前言 本文主要介绍了python中容易面临的考试点和犯错点&#xff0c;即浅拷贝与深拷贝 首先&#xff0c;针对Python中的可变对象来说&#xff0c;例如列表&#xff0c;我们可以通过以下方式进行浅拷贝和深拷贝操作&#xff1a; import copya [1, 2, 3, 4, [a, b]]b a …

小众实用!5款不为人知的Windows软件,让你工作更轻松

分享5款冷门但值得下载的Windows软件&#xff0c;个个都是实用&#xff0c;你可能一个都没见过&#xff0c;但是 我觉得你用过之后可能就再也离不开了。 1.键盘可视化——Keyviz Keyviz是一款免费开源的小工具&#xff0c;它的作用是可以实时展示键盘的操作&#xff0c;就可以…

编程语言分类

目录 ❤ 机器语言 机器语言的编程 ❤ 汇编语言 ❤ 高级语言(编程语言) 编译型 解释型 ❤ 动态语言和静态语言 ❤ 强类型定义语言和弱类型定义语言 ❤ 主流语言介绍 C语言 C java python JavaScript SQL PHP python从小白到总裁完整教程目录:https://blog…

浅入浅出keepalived+mysql实现高可用双机热备

当数据库发生宕机的情况&#xff0c;如果配置了数据库主从同步模式或主主同步模式&#xff0c;则可以从从库中获取数据。 当数据库发生宕机的情况&#xff0c;要求应用系统实现高可用&#xff0c;应用系统不会受到影响&#xff0c;需要对mysql进行双机热备实现数据库的高可用。…

断点调试(debug)

目录 F8案例 ​编辑 debug过程中报错 ​编辑用debug查看方法源码 一层一层查看 Arrays.sort()方法 F9 DebugExercise 介绍&#xff1a;断点调试是指在程序的某一行设置一个断电&#xff0c;调试时&#xff0c;程序运行到这一行就会停住&#xff0c;然后可以一步步往下调试…

微服务引擎 MSE 企业版全新升级

作者&#xff1a;流士 随着企业应用大规模云上迁徙与应用微服务化步伐加快&#xff0c;微服务治理的重要性对企业不言而喻&#xff0c;但微服务治理本身的规范化与标准化尚未形成&#xff0c;导致很多企业在微服务治理方面正经历着痛苦的试错期&#xff0c;甚至难以满足线上环境…

工作日志day03

同时构建静态和动态库 //如果用这种方式&#xff0c;只会构建一个动态库&#xff0c;虽然静态库的后缀是.a ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC}) ADD_LIBRARY(hello STATIC ${LIBHELLO_SRC}) //修改静态库的名字&#xff0c;这样是可以的&#xff0c;但是我们往往希望他…

RK3568平台开发系列讲解(显示篇)DRM的atomic接口

🚀返回专栏总目录 文章目录 一、Property二、Standard Properties三、代码案例沉淀、分享、成长,让自己和他人都能有所收获!😄 📢目前DRM主要推荐使用的是 Atomic(原子的) 接口。 一、Property Property(属性)—– Atomic操作必须依赖的基本元素 Property把前面的…

【教学典型案例】28.生产环境nginx限制上传大小

目录一&#xff1a;背景介绍二&#xff1a;Nginx限制上传大小1、Nginx官方文档说明2、设置参数1&#xff09;、在server模块中设置2&#xff09;、在http模块中设置三&#xff1a;问题分析过程四&#xff1a;总结一&#xff1a;背景介绍 二&#xff1a;Nginx限制上传大小 1、N…

X264简介-Android使用(二)

X264简介-Android使用&#xff08;二&#xff09; 4、Ubuntu上安装ffmpeg&#xff1a; 检查更新本地软件包&#xff08;如果未更新&#xff0c;reboot Vmware&#xff09;&#xff1a; sudo apt update sudo apt upgrade官网下载的source文件安装&#xff1a; http://ffmpe…

基于JSP的网上书城

技术&#xff1a;Java、JSP等摘要&#xff1a;随着科技的迅速发展&#xff0c;计算机技术已应用到社会的各个领域。随着计算机技术和通信技术的迅速发展&#xff0c;网络的规模也逐渐增大&#xff0c;网络的元素也随之不断增加&#xff0c;有的利用其通信&#xff0c;有的利用其…

【C++】30h速成C++从入门到精通(IO流)

C语言的输入与输出C语言中我们用到的最频繁的输入输出方式就是scanf ()与printf()。 scanf(): 从标准输入设备(键盘)读取数据&#xff0c;并将值存放在变量中。printf(): 将指定的文字/字符串输出到标准输出设备(屏幕)。注意宽度输出和精度输出控制。C语言借助了相应的缓冲区来…

网络协议丨从物理层到MAC层

我们都知道TCP/IP协议其中一层&#xff0c;就是物理层。物理层其实很好理解&#xff0c;就是物理攻击的物理。我们使用电脑上网时的端口、网线这些都属于物理层&#xff0c;没有端口没有路由你没有办法上网。网线的头我们叫水晶头&#xff0c;也是物理层的一份子。如果你的面前…

认识CSS之基础选择器

&#x1f31f;所属专栏&#xff1a;前端只因变凤凰之路&#x1f414;作者简介&#xff1a;rchjr——五带信管菜只因一枚&#x1f62e;前言&#xff1a;该系列将持续更新前端的相关学习笔记&#xff0c;欢迎和我一样的小白订阅&#xff0c;一起学习共同进步~&#x1f449;文章简…

SpringCloud——Hystrix 从入门到辗转反侧

SpringCloud-Hystrix 服务故障的“雪崩”效应 微服务的“扇出” 多个微服务之间的关联调用称为服务"扇出"。例如微服务A调用微服务B和微服务C&#xff0c;微服务B和微服务C又调用其他的微服务。 由于网络原因或者自身的原因&#xff0c;服务并不能保证 100% 可用&…

fork的黑科技,它到底做了个啥,源码级分析linux内核的内存管理

最近一直在学习linux内核源码&#xff0c;总结一下 https://github.com/xiaozhang8tuo/linux-kernel-0.11 一份带注释的源码&#xff0c;学习用。 fork的黑科技&#xff0c;它到底做了个啥&#xff0c;源码级分析linux内核的内存管理 先导知识&#xff0c;操作系统&#xff1…

提高生活质量,增加学生对校园服务的需求,你知道有哪些?

随着电子商务平台利用移动互联网的趋势提高服务质量&#xff0c;越来越多的传统企业开始关注年轻大学生消费者的校园市场。 提高生活质量&#xff0c;增加学生对校园服务的需求 大学生越来越沉迷于用手机解决生活中的“吃、喝、玩、乐”等服务&#xff0c;如“吃、喝”——可…

gitlab中文社区

1、获取gitlab中文社区项目 中文社区版项目&#xff1a;https://gitlab.com/xhang/gitlab 2、克隆中文仓库 git clone https://gitlab.com/xhang/gitlab.git 3、查看gitlab版本 diff 获取对应版本的中文 head -1 /opt/gitlab/version-manifest.txt #安装的是gitlab-ce…

网络拓扑结构的简单介绍

网络拓扑(Network Topology)就是根据网络节点的业务量和所需的信息流特性&#xff0c;确定它们之间的位置关系和连接方式。网络拓扑结构是指用传输介质互连各种设备的物理布局&#xff0c;指构成网络的成员间特定的物理的(真实的)&#xff0c;或者逻辑的(虚拟的)排列方式。 为什…