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

https://github.com/DoasIsay/ToyCoroutine

 

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

一个C/C++协程库的思考与实现之协程的简单调度_第1张图片

 

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

 

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

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

一个C/C++协程库的思考与实现之协程的简单调度_第2张图片

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

 

在调度器中加入一个先进先出的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的代码中可以写出这样的代码了,这实在是太酷了唉

一个C/C++协程库的思考与实现之协程的简单调度_第3张图片

 

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

一个C/C++协程库的思考与实现之协程的简单调度_第4张图片

 

 

你可能感兴趣的:(C++,协程,并发编程,c++,epoll,协程,网络,多线程)