8802 字
44 分钟
5.1IO管理概述

在学习本节时,请读者思考:I/O管理需要完成哪些核心功能?

5.1.1 I/O设备#

I/O设备管理是操作系统中最复杂且多样化的部分,其核心是通过软硬件协作,屏蔽不同设备的物理差异,使应用程序能以统一方式使用各类设备。一个I/O设备通常由两部分组成:设备本身和设备控制器。设备本身是执行具体输入或输出操作的物理装置(如磁盘的盘片与磁头);设备控制器则是连接到系统总线上的专用电路(如接口芯片),负责将操作系统发出的抽象命令(如“读取第x个扇区”)转换为设备可识别的电信号,并协调主机与设备间的数据传输。通过这种设计,操作系统无须了解各类设备的具体细节,即可统一管理它们。

1. 设备的分类#

I/O设备是指能够向计算机输入数据或接收其输出数据的外部设备。I/O设备类型多样,可从不同角度进行分类。

(1) 按信息交换单位分类#

  1. 块设备。以固定大小的数据块为单位进行信息交换,如磁盘等。其基本特征是传输速率较高、支持随机访问(可寻址),允许对任意数据块进行读/写操作。
  2. 字符设备。以字符(或字节)为单位进行信息交换,如交互式终端、打印机等。其基本特征是传输速率较低、不可寻址,通常采用中断方式实现异步通信。

(2) 按传输速率分类#

  1. 低速设备。传输速率仅为每秒几字节至数百字节,如键盘、鼠标等。
  2. 中速设备。传输速率为每秒数千字节至数十千字节,如激光打印机等。
  3. 高速设备。传输速率可达每秒数百千字节至数百兆字节(甚至更高),如磁盘等。

(3) 按使用特性分类#

  1. 人机交互设备。用于用户与计算机之间的信息交互,如键盘、显示器、打印机等。
  2. 存储设备。用于持久化存储数据,如磁盘、磁带、光盘等。
  3. 网络通信设备。用于计算机间通信,如网卡、调制解调器等。

(4) 按共享属性分类#

  1. 独占设备。任一时刻仅允许一个进程使用。一旦分配给某进程,即由该进程独占,直至使用完毕后释放。典型的独占设备多为低速设备,如打印机。
  2. 共享设备。允许多个进程在逻辑上并发访问。尽管物理访问仍需调度协调,系统可将其分配给多个进程分时交替使用。磁盘是典型的共享设备。
  3. 虚拟设备。通过 SPOOLing 技术,将独占设备改造为多个逻辑设备,使多个进程能并发使用。其实质是利用高速共享设备(如磁盘)作为缓冲区,实现独占设备的逻辑共享

2. I/O接口#

I/O接口(也称设备控制器)是CPU与设备之间的“桥梁”,用于实现计算机与设备之间的数据交换。它接收CPU发出的命令,控制设备工作,使CPU得以从烦琐的设备控制事务中解脱出来。设备控制器主要由如下三部分组成。

  1. 设备控制器与CPU的接口。用于实现CPU与设备控制器之间的通信。该接口包括三类信号线:数据线、地址线和控制线。数据线用于传输读/写数据、控制和状态信息;地址线用于指定I/O接口中的寄存器编号;控制线用于传送读/写等控制信号。
  2. 设备控制器与设备的接口。一个设备控制器可连接一个或多个设备,因此内部包含一个或多个设备接口。每个接口均可传输数据、控制和状态三类信号。
  3. I/O逻辑。用于实现对设备的控制。它通过控制线与CPU交互,对接收的I/O命令进行译码,并依据目标地址识别相应设备。CPU启动设备时,向控制器发送启动命令及目标地址,由I/O逻辑完成解析并控制指定的设备。

设备控制器的主要功能有:

  1. 接收并识别命令,例如磁盘控制器可响应CPU发出的读、写、寻道等命令;
  2. 完成数据交换,包括CPU与控制器之间以及控制器与设备之间的数据传输;
  3. 标识并报告设备状态,供CPU查询与处理;
  4. 地址识别
  5. 数据缓冲
  6. 差错控制

以磁盘控制器为例:当它接收到一条读命令(如“读取第11408个扇区”)后,会自动将线性扇区号转换为对应的柱面号、盘面号和扇区号,并控制磁头定位、等待旋转延迟、读取数据,最终将数据可靠地传送到内存。操作系统只需发出命令,而无须关心底层硬件的具体实现细节。

3. I/O接口的类型#

从不同角度看,I/O接口可分为以下类型。

  1. 按数据传送方式(设备与接口一侧),可分为并行接口(一个字节或一个字的所有位同时传送)和串行接口(一位一位地有序传送),接口需完成相应的并/串或串/并格式转换。
  2. 按主机访问设备的控制方式,可分为程序查询接口中断接口DMA接口等。
  3. 按功能灵活性,可分为可编程接口(通过编程改变接口功能)和不可编程接口
  4. 按设备类型的不同,可分为字符设备接口块设备接口网络设备接口

4. I/O端口#

I/O端口是指设备控制器中可被CPU访问的寄存器,主要包括以下三类:

  • 数据寄存器:缓存从设备送来的输入数据,或暂存CPU发出的输出数据。
  • 状态寄存器:保存设备的状态或执行结果,供CPU读取。
  • 控制寄存器:由CPU写入,用于启动操作或设置设备的工作模式。

为使CPU能够访问I/O端口,必须对各端口进行编址,每个端口对应一个唯一的端口地址。常见的编址方式主要有独立编址统一编址两种。

(1) 独立编址(I/O映射方式)#

独立编址为I/O端口建立一个独立于主存的地址空间。I/O端口地址与内存地址在逻辑上完全分离,地址值可以相同,但由于属于不同地址空间,不会发生冲突。CPU通过专用的I/O指令(如x86中的IN和OUT)访问I/O端口,指令中的地址字段指定端口号。

优点:I/O端口数量远少于内存单元,所需地址线较少,译码电路简单,寻址速度快;使用专用I/O指令,使程序中的I/O操作清晰可辨,便于阅读与调试。 缺点:I/O指令功能有限,通常仅支持简单的数据传输,程序设计灵活性较差;CPU需同时提供存储器读/写I/O读/写两组控制信号,增加了控制逻辑的复杂性。

(2) 统一编址(内存映射方式)#

统一编址将部分主存地址空间分配给I/O端口,使I/O端口与内存单元共享同一地址空间。通过地址范围即可区分访问目标(如高地址段映射到I/O设备),因此无须专用I/O指令,CPU使用普通的访存指令(如加载和存储指令)即可访问I/O端口。

优点:无须专用I/O指令,使得编程更加灵活;I/O端口可获得较大的编址空间;I/O访问的保护机制可由虚拟存储管理系统统一实现,无须额外硬件支持。 缺点:I/O端口占用主存地址空间,减少了系统可用内存容量;由于需根据完整地址判断是否为I/O区域,译码电路相对复杂,通常会降低译码速度。

5.1.2 I/O控制方式#

I/O控制是指控制设备和主机之间的数据传送。在I/O控制方式的发展过程中,始终贯穿着这样一个宗旨:尽量减少CPU对I/O控制的干预,将CPU从繁杂的I/O控制事务中解脱出来,以便其能更多地去执行运算任务。I/O控制方式共有4种,下面分别加以介绍。

1. 程序直接控制方式#

CPU对I/O 设备的控制采取轮询的I/O方式,也称程序轮询方式。CPU向设备控制器发出一条I/O指令,从I/O设备读取一个字(节),然后不断地循环测试设备状态(称为轮询),直到确定该字(节)已在设备控制器的数据寄存器中。于是CPU将数据寄存器中的数据取出,送入内存的指定单元,这样便完成了一个字(节)的I/O操作。

这种方式简单且易于实现,但缺点也很明显。CPU的绝大部分时间都处于等待I/O设备状态的循环测试中,CPU和I/O设备只能串行工作,由于CPU和I/O设备的速度差异很大,导致CPU的利用率相当低。而CPU之所以要不断地测试I/O设备的状态,就是因为在CPU中未采用中断机制,使I/O设备无法向CPU报告它已完成了一个字(节)的输入操作。

2. 中断驱动方式#

中断驱动方式的思想是允许I/O设备主动打断CPU的运行并请求服务,从而“解放”CPU,使得CPU向设备控制器发出一条I/O指令后可以继续做其他有用的工作。如图5.3(b)所示,我们从设备控制器和CPU两个角度分别来看中断驱动方式的工作过程。

从设备控制器的角度来看:设备控制器从CPU接收一个读命令,然后从设备读数据。一旦数据读入设备控制器的数据寄存器,便通过控制线向CPU发出中断信号,表示数据已准备好,然后等待CPU请求该数据。设备控制器收到CPU发出的取数据请求后,将数据放到数据总线上,传到CPU的寄存器中。至此,本次I/O操作完成,设备控制器又可开始下一次I/O操作。

从CPU的角度来看:当前运行进程发出读命令,该进程将被阻塞,然后保存该进程的上下文,转去执行其他程序。在每个指令周期的末尾,CPU检查中断信号。当有来自设备控制器的中断时,CPU保存当前运行进程的上下文,转去执行中断处理程序以处理该中断请求。中断处理程序从设备控制器的数据寄存器中读取一个字节(或字),并将其写入内核的缓冲区。处理完成后,系统解除原I/O请求进程的阻塞状态,并恢复相应进程的上下文以继续执行。

相比于程序轮询I/O方式,在中断驱动I/O方式中,设备控制器通过中断主动向CPU报告I/O操作已完成,不再需要轮询,在设备准备数据期间,CPU和设备并行工作,CPU的利用率得到明显提升。但是,中断驱动方式仍有两个明显的问题:

  1. 设备与内存之间的数据交换都必须经过CPU中的寄存器;
  2. CPU是以字(节)为单位进行干预的,若将这种方式用于块设备的I/O操作,则显然是极其低效的。

因此,中断驱动I/O方式的速度仍然受限。

3. DMA方式#

DMA(直接存储器存取)方式的核心思想是在I/O设备与内存之间建立直接数据通路,彻底“解放”CPU。其特点如下:

  1. 基本传送单位是数据块,而不再是字(节)。
  2. 数据直接在设备与内存之间传输,而不再经过CPU。
  3. 仅在数据块传送开始和结束时需要CPU干预。

为实现设备与内存之间直接交换成块的数据,DMA控制器需包含以下四类寄存器:

  1. 命令/状态寄存器(CR)。暂存CPU发来的I/O命令或设备状态。
  2. 内存地址寄存器(MAR)。存放数据在内存中的起始地址。输入时(设备→内存),表示数据要写入内存的目标地址;输出时(内存→设备),表示数据从内存读取的源地址。
  3. 数据寄存器(DR)。暂存单次传输的数据单元(如一个字)。
  4. 数据计数器(DC)。记录本次需传送的字(节)总数。

DMA方式的工作过程如下:CPU收到设备的DMA请求后,向DMA控制器发送启动命令,并设置MAR和DC的初值,随后启动DMA控制器。接着,CPU将I/O控制权交予DMA控制器,转而执行其他任务。DMA控制器接管总线后,以突发方式将整块数据在设备与内存之间直接传输,无须CPU干预。传输结束后,DMA控制器向CPU发送中断信号,通知操作完成。因此,CPU仅在数据传送的开始和结束阶段介入。

DMA方式的优点:数据以“块”为单位传输,相比中断方式,CPU干预频率进一步降低;数据也不再经过CPU寄存器,CPU与设备的并行程度进一步提升。

*4. 通道控制方式#

I/O通道是一种专用处理机,能够执行存放在主存中的通道程序(由一系列专用通道指令组成)。设置通道后,CPU仅需向通道发送一条I/O指令,指明目标设备及通道程序在内存中的起始地址。通道收到该指令后,便自主执行通道程序,完成全部I/O操作,并在结束后向CPU发出中断请求。由此,CPU、通道与I/O设备可高效并行工作,显著提升系统资源利用率。

通道与通用处理机的区别:通道的指令集专用于I/O控制,功能单一;它不具备独立的主存储器,其通道程序和数据均存放在主机内存中,且所有访存操作均受CPU控制。

通道与DMA方式的区别:DMA需由CPU预设数据块大小、内存始址等参数;而通道通过执行程序动态确定参数,能自主完成涉及多台设备、多个阶段的复杂I/O任务。此外,每个DMA控制器通常仅服务于一台设备,而一个通道可同时管理多台设备与内存之间的数据交换。

每种方式的优点都在于解决了前一种方式的主要缺点。总体而言,I/O控制方式的发展过程,就是要尽量减少CPU对I/O过程的干预,将CPU从繁杂的I/O控制事务中解脱出来。

下面通过一个形象的例子总结这几种I/O方式。想象一位客户要去裁缝店定制一批衣服的情形。采用程序直接控制方式时,裁缝没有客户的联系方式,客户只能每隔一段时间亲自去店里查看衣服是否做好,白白浪费大量时间。采用中断驱动方式时,裁缝有了客户的联系方式,每做完一件衣服就打电话通知客户来取,相比轮询方式,客户省去了反复跑腿的麻烦,但每件衣服都要跑一趟,依然效率不高。采用DMA方式时,客户花钱雇了一位秘书,并交代好:所有衣服先暂存在指定仓库,裁缝直接与秘书对接,由秘书负责取回衣服并入库,每处理完100件衣服,秘书才向客户汇报一次,从而大幅节省了客户的时间。采用通道方式时,客户交给秘书一份详细的办事清单(通道程序),秘书不仅能自主决定衣服存放的位置,还能根据清单灵活安排汇报时机。例如,是每完成100件还是10000件再通知客户,均由秘书自行判断。此外,一位DMA类秘书通常只能对接一位裁缝,而通道类秘书则可同时协调多位裁缝的工作。

5.1.3 I/O软件层次结构#

I/O软件涉及面很广,向下与硬件密切相关,向上又与虚拟存储器系统、文件系统及用户直接交互,各类I/O操作均需通过I/O软件实现。

为使复杂的I/O软件具备清晰的结构、良好的可移植性和适应性,现代操作系统普遍采用层次化的I/O软件设计。系统将设备管理模块划分为若干层次,每层利用其下层提供的服务,完成输入/输出功能中的特定子任务,并屏蔽其实现细节,向上层提供统一接口。只要层间接口保持不变,任一层的修改都不会影响其他层次,仅最低层涉及硬件的具体特性。整个I/O软件可视为具有4个层次的系统结构,各层次及其功能如下:

1. 用户层软件#

实现与用户的交互接口。用户可直接调用用户层提供的I/O库函数(如与I/O操作相关的标准库函数)对设备进行操作。通常,大部分I/O软件位于操作系统内核,但仍有一小部分驻留在用户层,例如与用户程序链接的库函数。用户层I/O软件必须通过系统调用获取操作系统服务。

2. 设备独立性软件#

设备独立性(也称设备无关性)是指应用程序在使用I/O设备时,无须依赖具体的物理设备。为实现这一特性,系统引入了逻辑设备物理设备的概念:应用程序使用逻辑设备名请求某类设备;系统在运行时,必须将逻辑设备名映射为实际的物理设备名。

使用逻辑设备名的优势在于:

  1. 提高设备分配的灵活性;
  2. 易于实现I/O重定向,I/O重定向是指用于I/O操作的设备可以更换(重定向),而不必修改应用程序。

为实现设备独立性,需在设备驱动程序之上设置一层设备独立性软件。该层的主要功能包括以下两个方面:

  1. 执行所有设备的公共操作,包括设备的分配与回收、逻辑设备名到物理设备名的映射、设备保护(禁止用户直接访问硬件)、缓冲管理、差错控制,以及提供统一大小的逻辑块,以屏蔽不同设备在信息交换单位和传输速率上的差异;
  2. 向用户层(或文件系统)提供统一的接口。通过这一层抽象,无论底层设备类型如何,应用程序均可使用统一的系统调用(如read/write)进行访问,显著增强了系统的可移植性与可维护性。

3. 设备驱动程序#

设备驱动程序与硬件直接相关,每类设备都需要配置一个专用的驱动程序。它作为I/O子系统与设备控制器之间的通信桥梁,向上层提供统一的操作接口,屏蔽不同设备控制器的差异。驱动程序的主要任务是:接收上层软件(如设备独立性层)发出的抽象I/O请求(例如read或write命令),将其转换为设备控制器能够识别的具体指令,启动设备执行相应操作,并将设备控制器返回的状态信息或数据传递回上层。其工作流程通常包括如下操作。

  1. 将抽象请求转换为具体操作。上层请求通常是逻辑性的(如“读取逻辑块5”),而设备控制器只能处理物理操作。驱动程序根据设备特性,将逻辑地址转换为物理参数。例如,磁盘驱动程序会将逻辑扇区号转换为柱面号、盘面号和扇区号。
  2. 校验请求的合法性。驱动程序检查操作是否允许。例如,禁止从只写设备(如打印机)读取数据,或向以只读方式打开的设备写入。若请求非法,则向上层返回错误。
  3. 检查设备状态。在启动I/O前,驱动程序读取设备控制器的状态寄存器,确认设备是否就绪。例如,写操作要求设备处于“接收就绪”状态;否则,进程需要等待。
  4. 传递参数。设备就绪后,驱动程序向控制器的相应寄存器写入命令、数据缓冲区地址、传输长度等参数。对于磁盘等复杂设备,所需传递的参数更多。
  5. 启动设备并处理后续。参数设置完成后,驱动程序向命令寄存器发送启动信号,设备开始工作。在多道程序系统中,当前进程随即被阻塞,CPU转去执行其他就绪进程,实现与I/O设备的并行;设备完成操作并发出中断后,由中断处理程序将其唤醒。

此外,驱动程序还负责设备的初始化、状态维护、错误处理以及与中断处理的配合,通过封装底层硬件细节,使上层软件无须了解设备的具体实现,即可使用统一接口访问各类I/O设备。

4. 中断处理程序#

当I/O操作完成时,设备控制器发出中断信号。CPU在执行完当前指令后响应中断,暂停当前进程,转去执行相应的中断处理程序;处理完毕后,再恢复原进程执行。整个过程如下。

  1. 检测并响应中断。设备完成一个数据单位(如字符或数据块)传输后,其控制器发出中断请求。CPU在指令周期末检测到中断信号时,即暂停当前进程,准备转入中断处理。
  2. 保护被中断进程的CPU现场。硬件自动将程序计数器(PC)和程序状态字(PSW)压入中断栈;随后,操作系统软件将其他CPU寄存器内容也保存至该栈。
  3. 转入相应设备的中断处理程序。CPU识别中断源,并跳转至对应设备的中断处理程序。
  4. 处理中断。程序读取设备控制器的状态寄存器,判断操作是否正常完成:若成功,则将设备数据寄存器中的内容传送到内存缓冲区;若异常,则进行错误处理。
  5. 恢复现场并返回。中断处理完成后,系统从中断栈恢复所有寄存器内容,CPU从被中断指令的下一条继续执行原进程。

为确保上述流程可靠运行,操作系统还需对中断处理程序本身进行管理,主要包括三个环节。

  1. 注册中断。驱动程序初始化时,需要向内核注册中断号及其处理函数入口地址,以建立硬件中断信号与服务代码之间的映射,确保中断发生时内核能准确调用相应处理例程。
  2. 处理中断。中断处理程序的典型流程:
    1. 确认中断是否由本设备产生;
    2. 清除控制器中的中断标志,防止重复触发;
    3. 执行必要的硬件操作,如读/写数据。由于运行在中断上下文中,处理程序必须快速、非阻塞,不得调用可能引起进程睡眠或调度的函数。
  3. 注销中断。当驱动程序被卸载或设备停用时,需要注销其中断处理程序以释放资源。若该中断请求线为独占,则注销后内核立即禁用该线;若该中断请求线为共享,则仅移除本设备的处理例程,该中断线需要等到所有关联设备均注销后,才会被最终禁用。

5. I/O操作举例#

类似于文件系统的层次结构,I/O子系统的层次结构也是需要掌握的重要内容,但不应死记硬背。为帮助读者理解,下面通过用户发起的一次write请求来说明各层的功能:

  1. 当用户要向某设备写入数据时,通过操作系统提供的write命令接口发起请求,该请求首先进入用户层软件
  2. 操作系统向上层提供的是统一的通用接口,即大多数设备都支持的标准命令,用户发出的write 请求首先由设备独立性层解析,然后传递给下一层。
  3. 不同类型设备对 write 命令的处理方式不同(如磁盘与打印机的行为差异显著),因此需由设备驱动层将通用的 write命令转换为设备特定的指令。
  4. 驱动程序将指令发送给设备控制器,启动实际的写操作;操作完成后,控制器向CPU发出中断信号,由中断处理程序响应。
  5. 中断处理程序确认写操作完成,清除中断标志,唤醒等待该操作的进程,并将结果逐层返回至用户程序,完成整个写操作。

上面从理论上说明了I/O请求在各层次间的传递过程。下面结合 Linux系统中一次 write系统调用的实际执行流程,具体分析各层如何协作以及CPU状态如何切换。

该流程始于用户空间对库函数的调用。用户程序调用 printf() 后,经标准库内部封装,最终触发 write 系统调用的封装函数。该函数生成的机器指令序列中包含一条陷阱指令(如IA-32架构下的 int $0x80)。在执行该指令之前,若干传送指令会将系统调用号及I/O参数(如文件描述符、缓冲区地址、字节数)写入指定寄存器(如eax)。CPU执行陷阱指令后,产生一个受控的软中断,硬件自动完成从用户态到内核态的模式切换,并将控制权移交给操作系统内核。

进入内核态后,CPU跳转至系统调用的统一入口程序 system_call()。该程序根据寄存器 eax中的系统调用号,通过跳转表将请求分派给对应的系统调用服务例程 sys_write()sys_write() 首先执行与设备无关的公共操作,如参数合法性检查、内核缓冲区分配与管理等。随后,它根据参数(如文件描述符)定位目标设备,并调用对应的设备驱动程序

设备驱动程序作为直接与设备控制器交互的模块,负责将抽象的I/O请求转换为设备可识别的具体命令。它初始化I/O接口、设置传输参数,并启动设备进行数据传输。随后,通常将当前进程置为阻塞态,并主动调用调度程序让出CPU,以便其他就绪进程运行。

传输完成后,设备控制器向CPU发出中断请求。CPU响应中断,暂停当前执行流,转入预设的中断服务程序。该程序读取设备状态,确认写操作是否成功,清除中断标志,并唤醒等待I/O的进程。中断处理完毕后,内核沿调用栈逐级返回。最终,在 system_call() 末尾通过执行 iret 等特权指令,CPU切换回用户态,并在用户空间中陷阱指令的下一条指令处恢复执行。

一次完整的I/O请求依次穿越了用户层软件系统调用接口设备独立性软件设备驱动程序中断处理程序,其中,陷阱指令是从用户态进入内核态的唯一合法入口,中断是设备通知操作完成、触发进程状态转换的核心机制。二者共同实现了用户态与内核态之间的安全切换。

5.1.4 应用程序I/O接口#

应用程序I/O接口是操作系统为统一管理各类I/O设备而设计的一套软件架构与编程规范,其主要目的有二:一是让应用程序(如执行文件打开操作)无须关心底层硬件的具体实现细节;二是使新设备能够以模块化的方式方便地加入系统,而无须改动内核代码。

1. I/O接口的分类#

操作系统将物理设备抽象为三种通用类型:字符设备、块设备和网络设备,并为每类设备提供标准的接口。设备间的具体差异由相应的驱动程序封装。下面分别介绍这三类设备接口。

(1) 字符设备接口#

字符设备是指数据的存取和传输以字符为单位的设备,如键盘、打印机等。其基本特征是传输速率较低、不可寻址,输入/输出通常采用中断驱动方式。

getput 操作:由于字符设备不可寻址,只能顺序存取,系统通常为其设置一个字符缓冲区。用户程序通过 get 操作从缓冲区读取字符,通过put操作向缓冲区写入字符。

in-control指令:字符设备种类繁多,差异较大,因此接口还提供一种通用的 in-control指令,(该指令包含多个参数),用于指定与具体设备相关的特定功能。

大部分字符设备属于独占设备,因此接口还需提供打开和关闭操作,以实现互斥共享。

(2) 块设备接口#

块设备是指数据的存取和传输以数据块为单位的设备,典型的块设备是磁盘。其基本特征是传输速率较高、可寻址。磁盘的I/O常采用DMA方式。

块设备接口将上层发来的抽象命令(如打开、读、写和关闭等)映射为设备能识别的具体操作。为简化上层访问,该接口隐藏了磁盘的物理二维结构(块地址用磁道号和扇区号表示),将所有扇区从0到n-1依次编号,从而将二维结构变为线性地址空间。

块设备接口的常用命令有 read()write()seek(),其中 seek() 命令用来指定下一个传输块。这三个命令描述了块设备的基本行为,使得应用程序不必关注这些设备的低层差别。

(3) 网络设备接口#

现代操作系统均提供网络通信的功能,为此需配备相应的网络软件和网络通信接口,使计算机能够与网络上的其他计算机通信或访问互联网。多数操作系统采用套接字(Socket)接口作为网络I/O的标准。应用程序通过套接字系统调用创建本地套接字,并将其连接到远程应用程序的套接字,从而建立通信通道,实现数据的发送与接收。

2. 阻塞I/O和非阻塞I/O#

操作系统的I/O接口还支持两种执行模式:阻塞与非阻塞。

阻塞I/O是多数操作系统默认采用的模式,原因是其编程模型简单、逻辑直观。当进程发起I/O请求时,若所请求的数据尚未就绪,则该进程立即被阻塞,并移入相应的等待队列;此后,进程无法执行任何其他任务,只能等待底层设备完成实际的数据传输。I/O操作完成后,内核将该进程移回就绪队列。当其再次获得CPU时,系统调用返回操作结果,进程继续后续处理。例如,你去咖啡店点单后,由于无法预知咖啡何时做好,只能原地等待,其间无法做其他事情。

优点:实现简单,适用于顺序处理或低并发场景。 缺点:I/O等待期间进程完全阻塞,CPU资源闲置,系统整体利用率较低。

非阻塞I/O是指当进程发起I/O请求时,内核不会阻塞该进程,而使系统调用立即返回。若数据尚未就绪,则调用将返回一个表示“暂无数据”的错误状态(如返回-1);进程可据此继续执行其他任务,并在时机适当时重试该操作。当某次重试时数据已就绪时,内核便将数据从内核缓冲区复制到用户空间,并返回实际成功传输的字节数。例如,吸取上次的教训,你在咖啡店点单后去逛商场,每隔一段时间回来询问“好了吗?”,其间可自由安排其他活动。

优点:进程在I/O等待期间不被阻塞,可执行其他任务,适合高并发或高响应性应用。 缺点:采用轮询方式频繁检查I/O状态,浪费CPU资源。

5.1.5 本节小结#

本节开头提出的问题的参考答案如下。

I/O管理需要完成哪些核心功能?

I/O管理需要完成以下4部分内容:

  1. 状态监控。实时掌握外部设备的工作状态(如忙、就绪、故障等)。
  2. 数据传输。协调并完成主机与设备之间的数据交换。
  3. 设备分配。在多用户或多进程环境下,负责设备的分配、共享与回收。
  4. 设备控制。通过设备驱动程序启动I/O操作,并处理设备返回的完成信号或故障中断。

评论