共计 2942 个字符,预计需要花费 8 分钟才能阅读完成。
1. 协程
协程是一种程序组件(以下称为微线程),通常我们把协程理解为自己实现调度,用于提高程序运行效率,降低开发复杂度的微线程。协程在用户态实现代码段的调度,不需要像线程一样切换到内核态进行调度,降低了对系统调度的依赖,减少了大量的中断和换页操作,从而降低了开发复杂度。开发者可以用同步的方式去进行代码开发,不需要考虑多线程模型的线程调度和诸多临界资源竞争问题。
协程在处理异步等待事件时有很大的优势,如 IO 的读写操作往往比较耗时,CPU 在遇到 IO 操作时需要切换线程,等待 IO 事件准备好之后再继续执行 IO 操作,如 socket 的连接,数据的收发,及文件的读写等都是比较频繁却比较耗时的操作,使用协程可以直接再用户态切换微线程,大大降低了微线程直接的调度过程,提高了代码的运行效率。
2.ST 的结构
2.1 st_thread
微线程上下文信息结构体,用于创建微线程执行代码段。
2.2 queue
RUNQ:队列中存储的是可以被调度运行的微线程,每次调度_st_vp_schedule 即从该队列取出一个 st_thread 去运行。
IOQ:存储处于 IO 等待状态的 threads,当上层调用 st_poll 时,将该 thread 放入 IOQ 中;当底层 epoll 有 IO 事件到达时,将该 thread 从 IOQ 中移除,并放入 RUNQ 中。
ZOMBIEQ:当 st_thread 退出时,放入 ZOMBIEQ 队列中
SLEEPQ: 当 st_poll 传入大于 0 的超时参数或者调用 st_usleep 和 st_cond_timewait 时,将 thread 加入到 SLEEPQ 中。
2.3 st_poll
用于监听各种 IO 事件,会根据系统能力不同而进行切换(kqueue、epoll、poll、select)
2.4 timer
用于记录各种超时和 st_sleep
2.5 vp_schedule
微线程调度切换函数,每次调用都会完成一次微线程切换。
3 接口详解
3.1 st_set_eventsys
函数原型:
int st_set_eventsys(int eventsys)
函数描述
设置协程事件通知机制,linux 下用 epoll,BSD 使用 kqueue。
参数 -eventsys
事件通知机制类型,取值如下:
ST_EVENTSYS_DEFAULT(0):使用库默认事件通知机制
ST_EVENTSYS_SELECT(1):使用 select 事件通知机制
ST_EVENTSYS_POLL(2):使用 poll 事件通知机制
ST_EVENTSYS_ALT(3):使用 alternate 备用的事件通知机制
函数返回值
成功返回 0,失败返回 -1
3.2 st_get_eventsys
函数原型:
int st_get_eventsys(void)
函数描述
获取协程事件通知机制,linux 下用 epoll,BSD 使用 kqueue。
函数返回值
事件通知机制类型,取值如下:
ST_EVENTSYS_DEFAULT(0):使用库默认事件通知机制
ST_EVENTSYS_SELECT(1):使用 select 事件通知机制
ST_EVENTSYS_POLL(2):使用 poll 事件通知机制
ST_EVENTSYS_ALT(3):使用 alternate 备用的事件通知机制
3.3 st_get_eventsys_name
函数原型:
const char *st_get_eventsys_name(void)
函数描述
获取协程事件通知机制的函数名称
函数返回值
返回协程事件通知机制的函数名称,如 epoll、kqueue、select、poll 等
3.4 st_init
函数原型:
int st_init(void)
函数描述
初始化协程库全局变量、队列、事件通知机制,并创建一个空闲协程
函数返回值
成功返回 0,失败返回 -1
3.5 _st_netfd_new
函数原型:
_st_netfd_t *_st_netfd_new(int osfd, int nonblock, int is_socket)
函数描述
根据文件描述符创建一个协程描述符结构体
参数 -osfd
文件描述符句柄
参数 -nonblock
是否阻塞,1 为阻塞,0 为非阻塞
参数 -is_socket
是否是 socket,1 为 socket,0 为非 socket
函数返回值
成功返回 0,失败返回 -1
3.6 st_netfd_poll
函数原型:
int st_netfd_poll(_st_netfd_t *fd, int how, st_utime_t timeout)
函数描述
让协程等待 IO 事件的到来,协程将停止执行,直到 IO 事件到来在继续执行。
参数 -fd
协程文件描述符指针
参数 -how
等待事件类型,取值如下:
POLLIN:等待数据写入事件
POLLOUT:等待数据写出事件
参数 -timeout
等待超时时间,单位为微妙
函数返回值
成功返回 0,失败返回 -1
3.7 st_accept
函数原型:
_st_netfd_t *st_accept(_st_netfd_t *fd, struct sockaddr *addr, int *addrlen, st_utime_t timeout)
函数描述
非阻塞式接收连接
参数 -fd
协程文件描述符指针
参数 -addr
对方 socket 地址,可为 NULL
参数 -addrlen
对方 socket 地址长度指针,可为 NULL
参数 -timeout
等待超时时间,单位为微妙
函数返回值
成功返回 0,失败返回 -1
3.8 st_connect
函数原型:
int st_connect(_st_netfd_t *fd, const struct sockaddr *addr, int addrlen, st_utime_t timeout)
函数描述
非阻塞式接连接 socket
参数 -fd
协程文件描述符指针
参数 -addr
对方 socket 地址
参数 -addrlen
对方 socket 地址长度指针
参数 -timeout
等待超时时间,单位为微妙
函数返回值
成功返回 0,失败返回 -1
3.9 st_read
函数原型:
ssize_t st_read(_st_netfd_t *fd, void *buf, size_t nbyte, st_utime_t timeout)
函数描述
非阻塞式读取 socket 数据
参数 -fd
协程文件描述符指针
参数 -buf
接收数据 buffer 指针
参数 -nbyte
接收 buffer 大小
参数 -timeout
等待超时时间,单位为微妙
函数返回值
成功返回 0,失败返回 -1
3.10 st_write
函数原型:
ssize_t st_write(_st_netfd_t *fd, const void *buf, size_t nbyte, st_utime_t timeout)
函数描述
非阻塞式读取 socket 数据
参数 -fd
协程文件描述符指针
参数 -buf
发送数据 buffer 指针
参数 -nbyte
发送 buffer 大小
参数 -timeout
等待超时时间,单位为微妙
函数返回值
成功返回 0,失败返回 -1
3.10 st_netfd_close
函数原型:
void srs_close_stfd(st_netfd_t& stfd)
函数描述
关闭协程文件描述符
参数 -stfd
协程文件描述符
函数返回值
无