初步了解Unix系统的I/O模式

I/O模式

对于一次IO访问(以read举例),数据会先被拷贝到操作系统内核的缓冲区中,然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间。
当一个read操作发生时,它会经历两个阶段:

  1. 等待数据准备
  2. 将数据从内核拷贝到进程中

因为这两个阶段,Unix系统的IO分为五种模式:

  • 阻塞 I/O(blocking IO)
  • 非阻塞 I/O(nonblocking IO)
  • I/O 多路复用( IO multiplexing)
  • 信号驱动 I/O( signal driven IO)
  • 异步 I/O(asynchronous IO)

阻塞 I/O

特点就是在IO执行的两个阶段,用户进程都被block了。
3e32b92ce427deecad87ec46df3bf039.png

Linux中,默认情况下所有的socket都是blocking

非阻塞 I/O

特点是用户进程要不断得通过系统调用询问内核,文件描述的数据是否准备好了,这种方式称为轮询(polling)。
如果数据还没有准备好,用户进程不会被阻塞,而是立刻返回一个error。用户进程收到error可以再次进行read操作。

I/O 多路复用

特点是单个用户进程可以处理多个 I/O 事件,减少多进程切换带来的系统开销。
分成三种形式:

  • select
  • poll
  • epoll

select 或者 poll 可以监视多个文件描述符,期间会被阻塞,任何一个描述符的数据准备好后通知用户进程,进程调用 recvfrom 把数据从内核复制到进程中。两者的区别是:

  • select基于数组实现,可以监视的文件描述符数量有限制
  • poll基于链表实现,可以监视的文件描述符数量没有限制

epoll 仅适用于 Linux系统,也可以监视多个文件描述符,内核通过回调函数把数据准备好的文件描述符放入链表,用户进程通过 epoll_wait() 检测到达链表的描述符,不需要轮询所有事件的文件描述符。
epoll又分两种模式:

  • LT,水平触发。当 epoll_wait() 检测到描述符事件到达时,会通知用户进程,进程可以不立即处理该事件,下次调用 epoll_wait() 会再次通知进程。是默认模式,同时支持 Blocking 和 No-Blocking。
  • ET,边缘触发。通知之后进程必须立即处理事件,下次再调用 epoll_wait() 时不会再得到事件到达的通知。效率比LT高,只支持 No-Blocking。

异步I/O

用户进程执行 aio_read 系统调用会立即返回,可以继续执行,不会被阻塞,内核会在I/O操作完成后向应用进程发送信号。

信号驱动I/O

用户进程使用 sigaction 系统调用后立即返回,可以继续执行,不会被阻塞,内核会在数据准备好后向应用进程发送信号。
用户进程收到信号后调用 recvfrom 将数据从内核复制到应用进程中。

参考

http://cyc2018.gitee.io/cs-notes/#/notes/Socket?id=poll

posted @ 2020-03-29 12:36  chzhyang  阅读(294)  评论(0编辑  收藏  举报