80-30 IO 模型-多路复用 基础

前提

在介绍 select、poll、epoll 前,有必要说说 linux(2.6+) 内核的事件 wakeup callback 机制,这是 IO 多路复用机制存在的本质。

Linux 通过 socket 睡眠队列来管理所有等待 socket 的某个事件的 process,同时通过 wakeup 机制来异步唤醒整个睡眠队列上等待事件的 process,通知 process 相关事件发生。

通常情况,socket 的事件发生的时候,其会顺序遍历 socket 睡眠队列上的每个 process 节点,调用每个 process 节点挂载的 callback 函数。在遍历的过程中,如果遇到某个节点是排他的,那么就终止遍历,总体上会涉及两大逻辑:

  1. 睡眠等待逻辑;
  2. 唤醒逻辑。

睡眠等待逻辑:涉及 select、poll、epoll_wait 的阻塞等待逻辑

  1. select、poll、epoll_wait 陷入内核,判断监控的 socket 是否有关心的事件发生了,如果没,则为当前 process 构建一个 wait_entry 节点,然后插入到监控 socket 的 sleep_list
  2. 进入循环的 schedule,直到关心的事件发生了
  3. 关心的事件发生后,将当前 process 的 wait_entry 节点从 socket 的 sleep_list 中删除。

唤醒逻辑

  1. socket 的事件发生了,然后 socket 顺序遍历其睡眠队列,依次调用每个wait_entry 节点的 callback 函数
  2. 直到完成队列的遍历或遇到某个 wait_entry 节点是排他的才停止。
  3. 一般情况下 callback 包含两个逻辑:
    1. wait_entry 自定义的私有逻辑;
    2. 唤醒的公共逻辑,主要用于将该 wait_entry 的 process 放入 CPU 的就绪队列,让CPU随后可以调度其执行。

select 和 poll 都属于 IO 多路复用,首先我们应该想一想为什么我们要用IO多路复用?

  • 首先,应用程序中同时处理多路输入输出流,若采用阻塞模式,将得不到预期的目的;
  • 若采用非阻塞模式,对多个输入进行轮询,但又太浪费CPU时间;
  • 若使用多进程,分别处理一条数据通路,将新产生进程间的同步与通信问题,使程序变得更加复杂;
  • 若使用多线程,又涉及到临界资源访问的问题,比较麻烦。比较好的方法是使用I/O多路复用。

文件描述符fd

文件描述符(File descriptor)是计算机科学中的一个术语,是一个用于表述指向文件的引用的抽象化概念。

文件描述符在形式上是一个非负整数。实际上,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。在程序设计中,一些涉及底层的程序编写往往会围绕着文件描述符展开。但是文件描述符这一概念往往只适用于UNIX、Linux这样的操作系统。


80-30 IO 模型-多路复用 基础
https://flepeng.github.io/010-network-80-30-IO-模型-多路复用-基础/
作者
Lepeng
发布于
2021年3月8日
许可协议