linux下的IO模型
前言
目前Linux下可用的IO模型有5种,分别为阻塞IO、非阻塞IO、IO多路复用、信号驱动IO、异步IO,其中较为成熟且高效、稳定的是IO多路复用模型,因此当前众多网络服务程序几乎都是采用这种IO操作策略。 当一个应用程序读写(以读为例)某端口数据时,选择不同IO模型的应用程序,其执行流程也将不同。
一、相关概念
1. 用户空间和内核空间
现代操作系统采用虚拟内存管理进程中的指令和数据,对于不同的操作系统,进程的虚拟内存大小也有所差异,比如32位操纵系统的虚拟内存为4G(2^32)。
操作系统的核心是内核(kernel),它拥有进程中最高的内存访问权限,也有底层硬件设备的所有操作权限,为保证内核的安全,操作系统将虚拟内存分为用户空间和内核空间,用户进程没有内核空间的直接访问权限。
以linux 32位操作系统为例,最高的1G内存被划分到内核空间(0xC0000000-0xFFFFFFFF),其余3G内存可以由进程使用,也就是用户空间(0x00000000-0xBFFFFFFF)。
2. 文件描述符
文件描述符也称文件句柄在形式上是一个非负整数。实际上,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。
内核利用文件描述符来访问文件,当打开现存文件或新建文件时,内核会返回一个文件描述符,文件描述符与包括相关信息(如文件的打开模式、文件的位置类型、文件的初始类型等)的文件对象相关联,这些信息被称作文件的上下文。
3. 阻塞和非阻塞
阻塞操作是指在执行设备操作时,若不能获得资源,则挂起进程直到满足可操作的条件后再进行操作。 被挂起的进程进入睡眠状态,被从调度器的运行队列移走,直到等待的条件被满足。
非阻塞操作的进程在不能进行设备操作时,直接退出,可以定时去查询当前是否可以操作,直至可以进行操作为止。
4. 同步和异步
同步操作是指在发出一个功能调用时,在没有得到结果之前,该调用就不返回。
异步操作是指在发出一个功能调用时,调用会立即返回,但此时并没有返回该功能的结果,直到有结果后再以通知的方式让调用者感知。
二、IO模型的分类
对于一次IO操作,一般会分为两个阶段,这里以read操作为例。
阶段1:数据会先被拷贝到内核缓冲区中(数据准备阶段)。
阶段2:再从内核缓冲区拷贝到进程的地址空间(数据读取阶段)。
1. 阻塞IO
进程调用IO函数后,由于数据没有准备好,进程需要一直阻塞,直到数据准备好了,IO函数将数据从内核空间拷贝到用户空间。
2. 非阻塞IO
进程调用IO函数后,如果当前数据没有准备好,IO函数直接返回,并以返回码的形式通知进程。随后进程定时调用IO函数,直到数据包准备好后将数据从内核空间拷贝到用户空间。
3. 信号驱动IO
进程对SIGIO注册信号处理函数,进程可以继续运行,不会阻塞,当数据准备好时会收到一个SIGIO信号,可以在信号处理函数中处理数据。
4. 异步IO
进程想操作系统提交一个异步IO请求,并立即返回,不需要等待操作完成,当数据准备好了,操作系统会将数据拷贝从内核空间拷贝到用户空间,并通知进程。
5. IO多路复用
进程通过select|poll|epoll等系统调用获取已就绪的文件描述符列表,相比于传统IO,IO多路复用模型中的单个线程可以同时监视多个IO操作,大大提高了IO操作的效率和并发性。
总结
本文仅对几种IO模型进行简单介,希望对大家有所帮助。