![](https://csdnimg.cn/release/download_crawler_static/10324651/bg5.jpg)
4 libco 的协程
通过上一节的例子,我们已经对 libco 中的协程有了初步的印象。我们完全可以把
它当做一种用户态线程来看待,接下来我们就从线程的角度来开始探究和理解它的实
现机制。
以 Linux 为例,在操作系统提供的线程机制中,一个线程一般具备下列要素:
(1) 有一段程序供其执行,这个是显然是必须的。另外,不同线程可以共用同一段
程序。这个也是显然的,想想我们程序设计里经常用到的线程池、工作线程,不同的工
作线程可能执行完全一样的代码。
(2) 有起码的“私有财产”,即线程专属的系统堆栈空间。
(3) 有“户口”,操作系统教科书里叫做“进(线)程控制块”,英文缩写叫 PCB。在
Linux 内核里,则为 task_struct 的一个结构体。有了这个数据结构,线程才能成为内核
调度的一个基本单位接受内核调度。这个结构也记录着线程占有的各项资源。
此外,值得一提的是,操作系统的进程还有自己专属的内存空间(用户态内存空
间),不同进程间的内存空间是相互独立,互不干扰的。而同属一个进程的各线程,则
是共享内存空间的。显然,协程也是共享内存空间的。
我们可以借鉴操作系统线程的实现思想,在 OS 之上实现用户级线程(协程)。跟
OS 线程一样,用户级线程也应该具备这三个要素。所不同的只是第二点,用户级线程
(协程)没有自己专属的堆空间,只有栈空间。首先,我们得准备一段程序供协程执行,
这即是 co_create() 函数在创建协程的时候传入的第三个参数——形参为 void*,返回值
为 void 的一个函数。
其次,需要为创建的协程准备一段栈内存空间。栈内存用于保存调用函数过程中
的临时变量,以及函数调用链(栈帧)。在 Intel 的 x86 以及 x64 体系结构中,栈顶由
ESP(RSP)寄存器确定。所以一个创建一个协程,启动的时候还要将 ESP(RSP)切到
分配的栈内存上,后文将对此做详细分析。
co_create() 调用成功后,将返回一个 stCoRoutine_t 的结构指针(第一个参数)。从
命名上也可以看出来,该结构即代表了 libco 的协程,记录着一个协程拥有的各种资源,
我们不妨称之为“协程控制块”。这样,构成一个协程三要素——执行的函数,栈内存,
协程控制块,在 co_create() 调用完成后便都准备就绪了。
5 关键数据结构及其关系
1 struct stCoRoutine_t {
2 stCoRoutineEnv_t *env;
3 pfn_co_routine_t pfn;
4 void *arg;
5 coctx_t ctx;
6
7 char cStart;
8 char cEnd;
9 char cIsMain;
10 char cEnableSysHook;
11 char cIsShareStack;
5