一个C/C++协程库的思考与实现之协程的简单调度

7 篇文章 0 订阅
2 篇文章 0 订阅

GitHub - DoasIsay/XCoroutine: 一个使用C/C++基于epoll实现的高性能的stackfull协程库,通过HOOK阻塞的系统调用,网络IO事件,协程间的同步事件及定时事件驱动协程的调度,通过汇编完成协程的高速切换,支持海量协程创建,支持协程的动态跨线程负载均衡调度,优先级调度,支持协程的栈上溢出检测及协程的signal信号处理机制,提供不同线程间协程同步协作的互斥量mutex,读写锁,条件变量cond,信号量sem,countDownLatch及用于数据共享的channel等等,总之很好玩,,,

提供这样的协程使用接口,实在令人,,,

0.0.1代码的accept协程只能写的这样丑陋,因为协程创建后立马调度执行占用了CPU,只有当协程读写网络IO将被阻塞时才会主动让出CPU,这时调度器会获得CPU,当有新连接到来时accept协程才会被调度器调度恢复执行,所以要在新创建一个协程前要先保存accept协程的上下文环境做为一个返回点,以便将来返回

对于这么丑陋的代码我耿耿于怀,事实是我写代码的水平也确实不怎么样,确实丑陋

但我还是想写出像创建多线程那样的代码,比如这样

要写出这样的代码,就需要把所有协程上下文的保存与恢复都在协程库中实现,不能让它出现在用户代码中,该如何做?

在调度器中加入一个先进先出的runQueue队列,协程创建后,先把协程push到队列,然后提供一个schedule接口,调用schedule接口后,控制权转移到调度器,调度器从runQueue,pop一协程运行,简直完美,流程如下:

  1. accept协程创建
  2. push此协程到runQueue,调用schedule接口,让出CPU控制权转移到调度器
  3. 调度器epoll_wait超时,从runQueue,pop出一协程调度运行
  4. accept协程运行,无连接可接收,让出CPU控制权转移到调度器,注册epoll读事件 ,然后epoll_wait等待事件或超时返回
  5. 客户端新建连接,epoll_wait返回读事件,调度器调度accept协程恢复执行
  6. accept协程接收连接,创建socketHandle协程,push协程到runQueue
  7. accept协程继续运行,同4
  8. epoll_wait超时,同3
  9. socketHandle协程被调度运行,开始read数据,无数据可read,让出CPU,控制权转移到调度器,注册epoll读事件,然后epoll_wait等待事件或超时返回

看,我所谓的协程调度就是如此的简单,first come first service

有了这个runQueue后我发现,好像可以创建调度无网络IO的协程了,0.0.1的代码只能创建调度网络IO协程,因为在读写不能满足,任务将被OS阻塞时是一个调度点,采用非阻塞的IO,当系统调用返回EAGAIN 或EWOULDBLOCK时表示当前操作无法满足,此时我们可以选择让协程主动让出CPU,把控制权转移到调度器,但无网络IO协程是没有IO读写的,因此就无法实现它的调度,所以只有runQueue显然还不能实现无网络IO协程的调度,还要提供一个类似schedule的接口,让当前协程主动让出CPU,那就是yield了

于是在0.0.2的代码中可以写出这样的代码了,这实在是太酷了唉

其实我并没找到yield接口有什么使用场景,实现yield接口只是因为觉得这种代码很酷而已,它还有一个使用场景就是可以写出如下代码做为一种周期性执行的任务,每次执行完任务后就yield让出CPU等待下一次调度,再加个timeout参数就是一个sleep了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值