OS: I/O: Blocking and Nonblocking

11th March 2021 at 10:08am

默认情况下,对一个 fd 做 read() write() 时,如果没有合适的数据读取、缓冲区空间不足以写入相应内容时,进程会阻塞住等待 I/O 完成,操作系统会把进程置为 sleep 状态并执行其他进程。

这在 server 场景下很不实用,因为一个 server 要处理大量的连接(即大量的 fd),如果读写一个 fd 就被 block 住,就无法处理大量的连接。

于是 Linux 提供了一个 flag O_NONBLOCK。对 fd 设置上该 flag 后,读写时如果数据未 ready,则操作系统不再阻塞,而是返回 EAGAIN 或是 EWOULDBLOCK 错误(这两者可以认为是一样的)。

如何对 fd 设置上 O_NONBLOCK 呢?

  • 对于通过 open() 获得的 fd,在 open() 的参数中传入 O_NONBLOCK
  • 对于不是通过 open() 的,比如 FIFO、socket 等,使用 fcntl() 来设置

非阻塞的 fd,如果不配合 I/O 多路复用 是没啥意义的。因为:

  • 如果你用一个无限的循环不停去查询该 fd 的状态,会浪费大量的 CPU
  • 如果你在循环中加入等待间隔,则对 fd 的处理不够及时

这都会使性能无法被利用好。