【操作系统】第六章-输入输出系统

六、输入输出系统

前言

I/O系统是OS的重要组成部分,用于管理诸如打印机和扫描仪等I/O设备,以及用于存储数据,如磁盘驱动器和磁带机等各种存储设备。由于I/O系统所含设备类型繁多,差异又非常大,致使I/O系统成为操作系统中最繁杂且与硬件最紧密相关的部分。

1.I/O系统的功能、模型和接口

1.1 I/O系统的基本功能

为了满足系统和用户的要求,I/O系统应具有下述几方面的基本功能,其中,第一、二方面的功能是为了方便用户使用I/O设备;第三、四方面的功能是用于提高CPU和I/O设备的利用率;第五、六方面的功能是为用户在共享设备时提供方便,以保证系统能有条不紊的运行,当系统发生错误时能及时发现错误,甚至能自动修正错误。

  1. 隐藏物理设备的细节
  2. 与设备的无关性
  3. 提供处理机和I/O设备的利用率
  4. 对I/O设备进行控制
  5. 确保对设备的正确共享
  6. 错误处理

1.2 I/O系统的层次结构和模型

  1. I/O软件的层次结构

    通常把I/O软件组织成四个层次,如下图,各层次及功能如下,图中的箭头表示I/O的控制流:

    (1) 用户层I/O软件,实现与用户交互的接口,用户可直接调用该层所提供的、与I/O操作有关的库函数对设备进行操作。

    (2) 设备独立性软件,用于实现用户程序与设备驱动器的统一接口、设备命名、设备的保护以及设备的分配与释放等,同时为设备管理和数据传送提供必要的存储空间。

    (3) 设备驱动程序,与硬件直接相关,用于具体实现系统对设备发出的操作指令,驱动I/O设备工作的驱动程序。

    (4) 中断处理程序,用于保存被中断进程的CPU环境,转入相应的中断处理程序进行处理,处理完毕再恢复被中断进程的现场后,返回到被中断的进程。

    在这里插入图片描述

  2. I/O系统中各种模块之间的层次视图

    在这里插入图片描述

1.3 I/O系统接口

  1. 块接口

    块设备接口是块设备管理程序与高层之间的接口。该接口反映了大部分磁盘存储器和光盘存储器的本质特征,用于控制该类设备的输入或输出。

    (1) 块设备。

    (2) 隐藏了磁盘的二维结构。

    (3) 将抽象命令映射为底层操作。

  2. 流设备接口

    流设备接口是流设备管理程序与高层之间的接口。该接口又称为字符设备接口,它反映了大部分字符设备的本质特征,用于控制字符设备的输入或输出。

    (1) 字符设备。

    (2) get和put操作。

    (3) in-control指令。

  3. 网络通信接口

    在现代OS中,都提供了面向网络的功能。但首先还需要通过某种方式把计算机连接到网络上。同时操作系统也必须提供相应的网络软件和网络通信接口,是计算机能通过网络与网络上的其它计算机进行通信或上网浏览。由于网络通信接口涉及到许多关于网络方面的知识,如网络中的网络通信协议和网络的层次结构等,故在后面网络操作系统中介绍。

2.I/O设备和设备控制器

I/O设备一般是由执行I/O操作的机械部分和执行控制I/O的电子部件组成。通常将这两部分分开,执行I/O操作的机械部分就是一般的I/O设备,而执行控制I/O的电子部件则称为设备控制器或适配器(adapter)。在微型机和小型机中的控制器常做成印刷电路卡形式,因而也常称为控制卡、接口卡或网卡,可将它插入计算机的扩展槽中。在有的大、中型计算机系统中,还配置了I/O通道或I/O处理机。

2.1 I/O设备

  1. I/O设备的类型

    (1) 按使用特性分类

    第一类是存储设备,也称外存、辅存,是用以存储信息的主要设备。该类设备存取速度较内存慢,但容量却大得多,价格也便宜。第二类就是I/O设备,它又可分为输入设备、输出设备和交互式设备。输入设备用来接收外部信息,如键盘、鼠标、扫描仪、视频摄像等。输出设备用于将计算机处理后的信息送向处理机外部的设备,如打印机、绘图仪等。交互式设备则是指集成的上述两类设备,主要是显示器,用于同步显示用户命令以及命令执行的结构。

    (2) 按传输速率分类

    按传输速度的高低,可将I/O设备分为三类。第一类是低速设备,其传输速率仅为每秒钟几个字节至数百个字节。典型的低速设备有键盘、鼠标器。第二类是中速设备,其传输速率在每秒钟数千个字节至数十万个字节。典型的中速设备有行式打印机、激光打印机等。第三类是高速设备,其传输速率在数十万字节至千兆字节。典型的高速设备有磁带机、磁盘机、光盘机等。

  2. 设备与控制器之间的接口

    通常,设备并不是直接与CPU进行通信,而是与设备控制器通信,因此,在I/O设备中应含有与设备控制器间的接口,在该接口中有三种类型的信号,各对应一条信号线,如下图。

    在这里插入图片描述

    (1) 数据信号线。

    (2) 控制信号线。

    (3) 状态信号线。

2.2 设备控制器

设备控制器的主要功能是,控制一个或多个I/O设备,以实现I/O设备和计算机之间的数据交换。它是CPU与I/O设备之间的接口,接收从CPU发来的命令,去控制I/O设备工作,使处理机能够从繁杂的设备控制事务中解脱出来。设备控制器是一个可编址的设备,当它仅控制一个设备时,它只有一个唯一的设备地址;若控制器可连接多个设备,则应含有多个设备地址,每一个设备地址对应一个设备。可把设备控制器分成两类:一类是用于控制字符设备的控制器,另一类是用于控制设备的控制器。

  1. 设备控制器的基本功能

    (1) 接收和识别命令。

    (2) 数据交换。

    (3) 标识和报告设备的状态。

    (4) 地址识别。

    (5) 数据缓冲区。

    (6) 差错控制。

  2. 设备控制器的组成

    (1) 设备控制器与处理机的接口。

    (2) 设备控制器与设备的接口。

    (3) I/O逻辑。

    在这里插入图片描述

2.3 内存映像I/O

驱动程序将抽象I/O命令转换出的一系列的命令、参数等数据装入设备控制器的相应寄存器,由控制器来执行这些命令,具体实施对I/O设备的控制。这一工作可用如下两种方法完成:

  1. 利用特定的I/O指令

  2. 内存映像I/O

    在这里插入图片描述

2.4 I/O通道

  1. I/O通道的引入

    虽然在CPU与I/O设备之间增加了设备控制器后,已能大大减少CPU对I/O的干预,但当主机所配置的外设很多时,CPU的负担仍然很重。为此,在CPU和设备控制器之间又增设了I/O通道(I/O Channel)。其主要目的是为了建立独立的I/O操作,不仅使数据的传送能独立于CPU,而且也希望有关对I/O操作的组织、管理及其结束处理尽量独立,以保证CPU有更多的时间去进行数据处理;或者说,其目的是使一些原来由CPU处理的I/O任务转由通道来承担,从而把CPU从繁杂的I/O任务中解脱出来。在设置了通道后,CPU只需向通道发送一条I/O指令,通道在收到该指令后,便从内存中取出本次要执行的通道程序,然后执行该通道程序,仅当通道完成了规定的I/O任务后,才向CPU发中断信号。

    实际上,I/O通道是一种特殊的处理机。它具有执行I/O指令的能力,并通过执行通道(I/O)程序来控制I/O操作。但I/O通道又与一般的处理机不同,主要表现在以下两个方面:一是其指令类型单一,这是由于通道硬件比较简单,其所能执行的命令,主要局限于与I/O操作有关的命令;二是通道没有自己的内存,通道所执行的通道程序是放在主机的内存中的,换而言之,是通道与CPU共享内存。

  2. 通道类型

    由于外围设备的类型较多,且其传输速率相差甚大,因而使通道具有多种类型。这里,根据信息交换方式的不同,可把通道分成以下三种类型。

    (1) 字节多路通道(Byte Multiplexor Channel)

    (2) 数组选择通道(Block Selector Channel)

    (3) 数组多路通道(Block Multiplexor Channel)

  3. “瓶颈”问题

    由于通道价格昂贵,致使机器中所设置的通道数量势必较少,这往往又使它成了I/O的瓶颈,进而造成整个系统吞吐量的下降。

    解决“瓶颈”问题的最有效的办法,便是增加设备到主机间的通路而不增加通道,换而言之,就是把一个设备连接到多个控制器上,而一个控制器连接到多个通道上。多通路方式不仅解决了“瓶颈”问题,而且提高了系统的可靠性,因为个别通道或控制器的故障不会使设备和存储器之间没有通路。

    在这里插入图片描述

3.中断机构和中断处理程序

中断在操作系统中有着特殊重要的地位,它是多道程序得以实现的基础,没有中断,就不可能实现多道程序,因为进程之间的切换是通过中断来完成的。另一方面,中断也是设备管理的基础,为了提高处理机的利用率和实现CPU与I/O设备并行执行,也必需有中断的支持。中断处理程序是I/O系统中最低的一层,它是整个I/O系统的基础。

3.1 中断简介

  1. 中断和陷入

    (1) 中断

    中断是指CPU对I/O设备发来的中断信号的一种响应。CPU暂停正在执行的程序,保留CPU环境后,自动地转去执行该I/O设备的中断处理程序。执行完后,再回到断点,继续执行原来的程序。I/O设备可以是字符设备,也可以是块设备、通信设备等。由于中断是由外部设备引起的,故又称外中断。

    (2) 陷入

    另外还有一种由CPU内部事件所引起的中断,例如进程在运算中发生了上溢或下溢,又如程序出错,如非法指令、地址越界,以及电源故障等。通常把这类中断称为内中断或陷入(trap)。与中断一样,若系统发现了有陷入事件,CPU也将暂停正在执行的程序,转去执行该陷入事件的处理程序。中断和陷入的主要区别是信号的来源,即是来自CPU外部,还是CPU内部。

  2. 中断向量表和中断优先级

    (1) 为了处理上的方便,通常是为每种设备配以相应的中断处理程序,并把该程序的入口地址放在中断向量表的一个表项中,并为每一个设备的中断请求规定一个中断号,它直接对应于中断向量表的一个表项中。当I/O设备发来中断请求信号时,由中断控制器确定该请求的中断号,根据该设备的中断号去查找中断向量表,从中取得该设备中断处理程序的入口地址,这样便可以转入中断处理程序执行。

    (2) 中断优先级

    然而实际情况是:经常会有多个中断信号源,每个中断源对服务要求的紧急程度并不相同,例如,键盘终端的中断请求的紧急程度不如打印机,而打印机中断请求的紧急程度又不如磁盘等。为此,系统就需要为它们分别规定不同的优先级。

  3. 对多中断源的处理方式

    对于多中断信号源的情况,当处理机正在处理一个中断时,又来了一个新的中断请求,这时应如何处理。例如,当系统正在处理打印机中断时,又收到了优先级更高的磁盘中断信号。对于这种情况,可有两种处理方式:屏蔽(禁止)中断与嵌套中断。

3.2 中断处理程序

当一个进程请求I/O操作时,该进程将被挂起,直到I/O设备完成I/O操作后,设备控制器便向CPU发送一个中断请求,CPU响应后便转向中断处理程序,中断处理程序执行响应的处理,处理完后解除相应进程的阻塞状态。

中断处理程序的处理过程可分为以下几个步骤:

(1) 测定是否有未响应的中断信号。

(2) 保护被中断进程的CPU环境。

(3) 转入相应的设备处理程序。

(4) 中断处理

(5) 恢复CPU的现场并退出中断。

在这里插入图片描述

4.设备驱动程序

4.1 设备驱动程序概述

  1. 设备驱动程序的功能

    为了实现I/O系统的高层与设备控制器之间的通信,设备驱动程序应具有以下功能:

    (1) 接收由与设备无关的软件发来的命令和参数,并将命令中的抽象要求转换为与设备相关的底层操作序列。

    (2) 检查用户I/O请求的合法性,了解I/O设备的工作状态,传递与I/O设备操作有关的参数,设备设备的工作方式。

    (3) 发出I/O命令,如果设备空闲,便立即启动I/O设备,完成指定的I/O操作;如果设备忙碌,则将请求者的请求块挂在设备队列上等待。

    (4) 及时响应由设备控制器发来的中断请求,并根据其中断类型,调用相应的中断处理程序进行处理。

  2. 设备驱动程序的特点

    (1) 驱动程序是实现在与设备无关的软件和设备控制器之间通信和转换的程序,具体说,它将抽象的I/O请求转换成具体的I/O操作后传送给控制器。又把控制器中所记录的设备状态和I/O操作完成情况,及时地反映给请求I/O的进程。

    (2) 驱动程序与设备控制器以及I/O设备的硬件特性紧密相关,对于不同类型的设备,应配置不同的驱动程序。但可以为相同的多个中断设置一个终端驱动程序。

    (3) 驱动程序与I/O设备所采用的I/O控制方式紧密相关,常用的I/O控制方式是中断驱动和DMA方式。

    (4) 由于驱动程序与硬件紧密相关,因而其中的一部分必须用汇编语言书写。目前很多驱动程序的基本部分已经固化在ROM中。

    (5) 驱动程序应允许重入。一个正在运行的驱动程序常会在一次调用完成前被再次调用。

  3. 设备处理方式

    在不同的操作系统中,所采用的设备处理方式并不完全相同。根据在设备处理时是否设置进程,已经设置什么样的进程,而把设备处理方式分为以下三类:

    (1) 为每一类设备设置一个进程,专门用于执行这类设备的I/O操作。

    (2) 在整个系统中设置一个I/O进程,专门用于执行系统中所有各类设备的I/O操作。也可以设置一个输入进程和一个输出进程,分别处理系统中的输入或输出操作。

    (3) 不设置专门的设备处理进程,而只为各类设备设置相应的设备驱动程序,供用户或系统进程调用。

4.2 设备驱动程序的处理过程

设备驱动程序的主要任务是启动指定设备,完成上层指定的I/O工作。但在启动之前,应先完成必要的准备工作,如检测设备状态是否为“忙”等。在完成所有的准备工作后,才向设备控制器发送一条启动命令。以下是设备驱动程序的处理过程:

(1) 将抽象要求转换为具体要求。

(2) 对服务请求进行校验。

(3) 检测设备的状态。

(4) 传送必要的参数。

(5) 启动I/O设备。

4.3 对I/O设备的控制方式

  1. 使用轮询的可编程I/O方式

  2. 使用中断的可编程I/O方式

  3. 直接存储器访问方式

    在这里插入图片描述

  4. I/O通道控制方式

5.与设备无关的I/O软件

5.1 与设备无关软件的基本概念

  1. 以物理设备名使用设备
  2. 引入了逻辑设备名
  3. 逻辑设备名称到物理设备名称的转换

5.2 与设备无关的软件

在与设备无关的软件中,包括了执行所有设备公用操作的软件,具体如下几项。

  1. 设备驱动程序的统一接口

    为了使所有的设备驱动程序有着统一的接口,一方面,要求每个设备驱动程序与OS之间都有着相同的接口,或者相近的接口,这样会使添加一个新的设备驱动程序变得很容易,同时在很大程度上方便了开发人员对设备驱动程序的编制。另一方面,要将抽象的设备名映射到适当的驱动程序上,或者说,将抽象的设备名转换为具体的物理设备名,并进一步可以找到相应物理设备的驱动程序入口。此外,还应对设备进行保护,禁止用户直接访问设备,以防止无权访问的用户使用。

  2. 缓冲管理

    无论是字符设备还是块设备,它们的运行速度都远低于CPU的速度。为了缓和CPU和I/O设备之间的矛盾、提高CPU的利用率,在现代OS中都无一例外地分别为字符设备和块设备配置了相应的缓冲区。缓冲区有着多种形式,如单缓冲区、双缓冲区、循环缓冲区、公用缓冲池等,以满足不同情况的需要。

  3. 差错控制

    由于设备中有着许多的机械和电气部分,因此,它们比主机更容易出现故障,这就导致I/O操作中的绝大多数错误都与设备有关。错误可分为如下两类:

    (1) 暂时性错误。

    (2) 持久性错误。

  4. 对独立设备的分配与回收

    在系统中有两类设备:独占设备和共享设备。对于独占设备,为了避免诸进程独占设备的争夺,必须由系统来统一分配,不允许进程自行使用。每当进程需要使用某(独占)设备时,必须先提出申请。OS接到对设备的请求后,先对进程所请求的独占设备进行检查,看该设备是否空闲。若空闲,才把该设备分配给请求进程。否则,进程将被阻塞,放入该设备的请求队列中等待。

  5. 独立于设备的逻辑数据块

    不同类型的设备,其数据交换单位是不同的,读取和传输速度也各不相同,如字符型设备以单个字符(字)为单位,块设备是以一个数据块为单位。即使同一类型的设备,其数据交换单位的大小也是有差异的,如不同磁盘由于扇区大小的不同,可能造成数据块大小的不一致。设备独立性软件应能够隐藏这些差异而被逻辑设备使用,并向高层软件提供大小统一的逻辑数据块。与设备无关软件的功能如下图所示。

    在这里插入图片描述

5.3 设备分配

  1. 设备分配中的数据结构

    (1) 设备控制表DCT

    系统为每一个设备都配置了一张设备控制表,用于记录设备的情况,如下图。

    在这里插入图片描述

    (2) 控制器控制表、通道控制表和系统设备表

    在这里插入图片描述

  2. 设备分配时应考虑的因素

    (1) 设备的固有属性

    ①独占设备的分配策略

    ②共享设备的分配策略

    ③虚拟设备的分配策略

    (2) 设备分配算法

    ①先来先服务

    ②优先级高者优先

    (3) 设备分配中的安全性

    ①安全分配方式

    ②不安全分配方式

  3. 独占设备的分配程序

    (1) 基本的设备分配程序

    当某进程提出I/O请求后,系统的设备分配程序可按下述步骤进行设备分配:

    ①分配设备。

    ②分配控制器。

    ③分配通道。

    (2) 设备分配程序的改进

    为获得设备的独立性,进程应使用逻辑设备名请求I/O。这样,系统首先从SDT中找出第一个该类设备的DCT。若设备忙,又查找第二个该类设备的DCT,仅当所有该类设备都忙时,才把进程挂在该类设备的等待队列上。

5.4 逻辑设备名到物理设备名映射的实现

为了实现与设备的无关性,应当用程序请求使用I/O设备时,应当用逻辑设备名。但系统只识别物理设备名,因此在系统中需要配置一张逻辑设备表,用于将逻辑设备名映射为物理设备名。

  1. 逻辑设备表LUT(Logical Unit Table)

    在逻辑设备表的每个表目中包含了三项:逻辑设备名、物理设备名和设备驱动程序的入口地址,如下图(a)。当进程用逻辑设备名请求分配I/O设备时,系统根据当时的具体情况,为它分配一台相应的物理设备。与此同时,在逻辑设备表上建立一个表目,填上应用程序中使用的逻辑设备名和系统分配的物理设备名,以及该设备驱动程序的入口地址。当以后进程再利用该逻辑设备名请求I/O操作时,系统通过查找LUT,便可找到该逻辑设备所对应的物理设备和该设备的驱动程序。

    在这里插入图片描述

  2. 逻辑设备表的设置问题

    在系统中可采取两种方式设置逻辑设备表:

    第一种方式,是在整个系统中只设置一张LUT。由于系统中所有进程的设备分配情况都记录在同一张LUT中,因而不允许在LUT中具有相同的逻辑设备名,这就要求所有用户都不能使用相同的逻辑设备名。在多用户环境下这通常是难以做到的,因而这种方式主要用于单用户系统中。

    第二种方式,是为每个用户设置一张LUT。每当用户登录时,系统便为该用户建立一个进程,同时也为之建立一张LUT,并将该表放入进程的PCB中。由于通常在多用户系统中都配置了系统设备表,故此时的逻辑设备表可以采用上图(b)中的格式。

6.用户层的I/O软件

6.1 系统调用与库函数

  1. 系统调用

    一方面,为使诸进程能有条不紊地使用I/O设备,且能保护设备的安全性,不允许运行在用户态的应用程序去直接调用运行在核心态(系统态)的OS过程。但另一方面,应用进程在运行时,又必须取得OS所提供的服务,否则,应用程序几乎无法运行。为了解决次矛盾,OS在用户层引入了一个中介过程——系统调用,应用程序可以通过它间接调用OS中的I/O过程,对I/O设备进行操作。

    系统中会有许多系统调用,它们的实现方法是基本相同的。下面简单说明系统调用的执行过程。当应用程序需要执行某种I/O操作时,在应用程序中必须使用相应的系统调用。当OS捕获到应用程序中的该系统调用后,便将CPU的状态从用户态转换到核心态,然后转向操作系统中相应过程,由该过程完成所需的I/O操作。执行完成后,系统又将CPU状态从核心态转换到用户态,返回到应用程序继续执行。下图示出了系统调用的执行过程。

    在这里插入图片描述

  2. 库函数

    在C语言中提供了多种类型的库函数,对于I/O方面,主要是对文件和设备进行度/写的库函数,以及控制/检查设备状态的库函数。显然这些库函数的集合也应是I/O系统的组成部分。而且我们可以这样来看待内核和库函数之间的关系:内核提供了OS的基本功能,而库函数扩展了OS内核,使用户能方便取得操作系统的服务。

6.2 假脱机(Spooling)系统

如果说,通过多道程序技术可将一台物理CPU虚拟为多台逻辑CPU,从而运行多个用户共享一台主机,那么,通过假脱机技术,则可将一台物理I/O设备虚拟为多台逻辑I/O设备,这样也就运行多个用户共享一台物理I/O设备。

  1. 假脱机技术

    为了缓和CPU的高速性和I/O设备低速性间的矛盾,而引入了脱机输入、脱机输出技术。该技术是利用专门的外围控制机,先将低速I/O设备上的数据传送到高速磁盘上,或者相反。这样当处理机需要输入数据时,便可以直接从磁盘中读取数据,极大地提高了输入速度。反之,在处理机需要输出数据时,也可以很快的速度把数据先输出到磁盘上,处理机便可去做自己的事情。

  2. SPOOLing的组成

    如前所述,SPOOLing技术是对脱机输入/输出系统的模拟,相应地,如下图所示,SPOOLing系统建立在通道技术和多道程序技术的基础上,以高速随机外存(通常为磁盘)为后援存储器。SPOOLing的工作原理如下图所示。

    在这里插入图片描述

    SPOOLing系统主要由以下四部分构成:

    (1) 输入井和输出井。

    (2) 输入缓冲区和输出缓冲区。

    (3) 输入进程和输出进程。

    (4) 井管理程序。

  3. SPOOLing系统的特点

    (1) 提高了I/O的速度。

    (2) 将独占设备改造为共享设备。

    (3) 实现了虚拟设备功能。

  4. 假脱机打印机系统

    打印机是经常用到的输出设备,属于独占设备。利用假脱机技术可将它改造为一台可供多个用户共享的打印设备,从而提高设备的利用率,也方便了用户。共享打印机技术已被广泛地用于多用户系统和局域网络中。假脱机打印系统主要有以下三部分:

    (1) 磁盘缓冲区。

    (2) 打印缓冲区。

    (3) 假脱机管理进程和假脱机打印进程。

    下图示出了假脱机打印机系统的组成。

    在这里插入图片描述

    利用假脱机系统向用户提供共享打印机的概念是:对每个用户而言,系统并非即时执行其程序输出数据的真实打印操作,而只是即时将数据输出到缓冲区,这是的数据并未真正被打印,只是让用户感觉系统已为他打印;真正的打印操作,是在打印机空闲且该打印任务在等待队列中已排在队首时进行的;而且,打印操作本身也是利用CPU的一个时间片,没有使用专门的外围机;以上的过程是对用户屏蔽的,用户是不可见的。

  5. 守护进程(daemon)

    前面是利用假脱机系统来实现打印机共享的一种方案,人们对该方案进行了某些修改,如取消该方案中的假脱机管理进程,为打印机建立一个守护进程,由它执行一部分原来由假脱机管理进程实现的功能,如为用户在磁盘缓冲区中申请一个空闲盘块,并将要打印的数据送入其中,将该盘块的首址返回给请求进程。另一部分由请求进程自己完成,每个要求打印的进程首先生成一份要求打印的文件,其中包含对打印的要求和指向装有打印输出数据盘块的指针等信息,然后将用户请求打印文件放入假脱机文件队列(目录)中。

    守护进程是允许使用打印机的唯一进程。所有需要使用打印机进行打印的进程都需要将一份要求打印的文件放在假脱机文件队列中。如果守护进程正在睡眠,便将它唤醒,由它按照目录中第一个文件中的说明进行打印,打印完成后,再按照目录中第二个文件中的说明进行打印,如此逐份文件地进行打印,直到目录中的全部文件打印完毕,守护进程无事可做,又去睡眠,等待用户进程再次发来打印请求。

    除了打印机守护进程之外,还可能有许多其他的守护进程,如服务器守护进程和网络守护进程等。事实上,凡是需要将独占设备改造为可供多个进程共享的设备时,都要为该设备配置一个守护进程和一个假脱机文件队列(目录)。同样,守护进程是运行使用该独占设备的唯一进程,所有其它进程都不能直接使用该设备,只能将对该设备的使用要求写入一份文件中,放在假脱机目录中。由守护进程按照目录中的文件依次来完成诸进程对该设备的请求,这样就把一台独占设备改造为可为多个进程共享的设备。

7.缓冲区管理

7.1 引入缓冲区的原因有很多,可归结为以下几点:

(1) 缓和CPU与I/O设备间速度不匹配的矛盾。

(2) 减少对CPU的中断频率,放宽对CPU中断响应时间的限制。

(3) 解决数据粒度不匹配的问题。

(4) 提高CPU和I/O设备之间的并行性

7.2 单缓冲区和双缓冲区

  1. 单缓冲区(Single Buffer)

    在单缓冲情况下,每当用户进程发出一I/O请求时,操作系统便在主存中为之分配一缓冲区,如下图。在块设备输入时,假定从磁盘把一块数据输入到缓冲区的时间为T,OS将该缓冲区中的数据传送到用户区的时间为M,而CPU对这一块数据处理(计算)的时间为C。由于T和C是可以并行的,当T>C时,系统对每一块数据的处理时间为M+T;反之则为M+C,故可以把系统对每一块数据的处理时间表示为Max(C, T)+M。

    在这里插入图片描述

  2. 双缓冲区(Double Buffer)

    由于缓冲区是共享资源,生产者与消费者在使用缓冲区时必须互斥。如果消费者尚未取走缓冲区中的数据,即使生产者又生产出新的数据,也无法将它送入缓冲区,生产者等待。如果为生产者与消费者设置了两个缓冲区,便能解决这一问题。

    为了加快输入和输出速度,提高设备利用率,人们又引入了双缓冲区机制,也称为缓冲对换(Buffer Swapping)。在设备输入时,先将数据送入第一缓冲区,装满后便转向第二缓冲区。此时操作系统可以从第一缓冲区中移除数据,并送入用户进程。接着由CPU对数据进行计算。在双缓冲时,系统处理一块数据的时间可以粗略地认为是Max(C, T),如果C<T,可使块设备连续输入;如果C>T,则可使CPU不必等待设备输入。对于字符设备,若采用行输入方式,则采用双缓冲通常能消除用户的等待时间,即用户在输入完第一行后,在CPU执行第一行中的命令时,用户可继续先第二缓冲区输入下一行数据。

    在这里插入图片描述

    如果在实现两台机器之间的通信时仅为它们配置了单缓冲,如下图,那么,它们之间在任一时刻都只能实现单向的数据传输。为了实现双向数据传输,必须在两台机器中都设置两个缓冲区,一个用作发送缓冲区,另一个用作接收缓冲区,如下图。

    在这里插入图片描述

7.3 环形缓冲区

当输入与输出的速度基本相匹配时,采用双缓存能获得较好的效果,可使生产者和消费者基本上能并行操作。但若两者的速度相差甚远,双缓冲的效果则不够理想,不过可以随着缓冲区数量的增加,使情况有所改善。因此,又引入了多缓冲机制,可将多个缓冲区组织成环形缓冲区形式。

  1. 环形缓冲区的组成

    (1) 多个缓冲区。

    (2) 多个指针。

  2. 环形缓冲区的使用

    计算进程和输入进程可利用下述两个过程来使用环形缓冲区。

    (1) Getbuf过程。当计算机进程要使用缓冲区中的数据时,可调用Getbuf过程。该过程将由指针Nextg所指示的缓冲区提供给进程使用,相应地,须把它改为现行工作缓冲区,并令Current指针指向该缓冲区的第一个单元,同时将Nextg移向下一个G缓冲区。类似地,每当输入进程要使用空缓冲区来装入数据时,也调用Getbuf过程,由该过程将指针Nexti所指示的缓冲区提供给输入进程使用,同时将Nexti指针移向下一个R缓冲区。

    (2) Releasebuf过程。当计算进程把C缓冲区中的数据提取完毕时,便调用Releasebuf过程,将缓冲区C释放。此时,把该缓冲区由当前(现行)工作缓冲区C改为空缓冲区R。类似地,当输入进程把缓冲区装满时,也应调用Releasebuf过程,将该缓冲区释放,并改为G缓冲区。

  3. 进程之间的同步问题

    使用输入循环缓冲,可使输入进程和计算进程并行执行。相应地,指针Nexti和指针Nextg将不断地沿着顺时针方向移动,这样就可能出现下述两种情况:

    (1) Nexti指针追赶上Nextg指针。这意味着输入进程输入数据的速度大于计算进程处理数据的速度,已把全部可用的空缓冲区装满,再无缓冲区可用。此时,输入进程应阻塞,直到计算进程把某个缓冲区中的数据全部提取完,使之成为空缓冲区R,并调用Releasebuf过程将它释放时,才将输入进程唤醒。这种情况被称为系统受计算限制。

    (2) Nextg指针追赶上Nexti指针。这意味着输入数据的速度低于计算进程处理数据的速度,使全部装有输入数据的缓冲区都被抽空,再无装有数据的缓冲区供计算进程提取数据。这时,计算进程只能阻塞,直到输入进程又装满某个缓冲区,并调用Releasebuf过程将它释放时,才去唤醒计算进程,这种情况被称为系统受I/O限制。

7.4 缓冲池(Buffer Pool)

上述的缓冲区是专门为特定的生产者和消费者设置的,它们属于专用缓冲。当系统较大时,应该有许多这样的循环缓冲,这不仅要消耗大量的内存空间,而且其利用率不高。为了提高缓冲区的利用率,目前广泛流行既可用于输入又可用于输出的公用缓冲池,在池中设置了多个可供若干进程共享的缓冲区。缓冲池与缓冲区的区别在于:缓冲区仅仅是一组内存块的链表,而缓冲池则是包含了一个管理的数据结构及一组操作函数的管理机制,用于管理多个缓冲区。

  1. 缓冲池的组成

    缓冲池管理着多个缓冲区,每个缓冲区由用于标识和管理的缓冲首部以及用于存放数据的缓冲体两部分组成。缓冲首部一般包含缓冲区号、设备号、设备上的数据块号、同步信号量以及队列链接指针等。为了管理上的方便,一般将缓冲池中具有相同类型的缓冲区链接成一个队列,于是可形成以下三个队列:

    (1) 空白缓冲队列emq。

    (2) 输入队列inq。

    (3) 输出队列outq。

    处理上述三个队列外,还应具有四种工作缓冲区:用于收容输入数据的工作缓冲区、用于提取输入数据的工作缓冲区、用于收容输出数据的工作缓冲区,以及用于提取输出数据的工作缓冲区。

  2. Getbuf过程和Putbuf过程

    在数据结构课程中,曾介绍过队列和对队列进行操作的两个过程,第一个是Addbuf(type, number)过程。该过程用于将由参数number所指示的缓冲区B挂在type队列上。第二个是Takebuf(type)过程。它用于从type所指示的队列的队首摘下一个缓冲区。

    这两个过程能否用于对缓冲池中的队列进行操作呢?答案是否定的。因为缓冲池中的队列本身是临界资源,多个进程在访问一个队列时,既应互斥,又须同步。为此,需要对这两个过程加以改造,以形成可用于对缓冲池中的队列进行操作的Getbuf和Putbuf过程。

    为使诸进程能互斥地访问缓冲池队列,可为每一队列设置一个互斥信号量MS(type)。此外,为了保证诸进程同步地使用缓冲区,又为每个缓冲队列设置了一个资源信号量RS(type)。既可实现互斥又可保证同步的Getbuf过程和Putbuf过程描述如下:

    void Getbuf(unsigned type) {
          
          
        Wait(RS(type));
        Wait(MS(type));
        B(number) = Takebuf(type);
        Signal(MS(type));
    }
    void Putbuf(type, number) {
          
          
        Wait(MS(type));
        Addbuf(type, number);
        Signal(MS(type));
        Signal(RS(tpye));
    }
    
  3. 缓冲区的工作方式

    缓冲区可以工作在如下四种工作方式,如下图所示。

    在这里插入图片描述

    (1) 收容输入。输入进程可调用Getbuf(emq)过程,从空缓冲队列emq的队首摘下一空缓冲区,把它作为收容输入工作缓冲区hin。然后,把数据输入其中,装满后再调用Putbuf(inq, hin)过程,将它挂在输入队列inq队列上。

    (2) 提取输入。计算进程可调用Getbuf(inq)过程,从输入队列inq的队首取得一缓冲区,作为提取输入工作缓冲区(sin)。计算进程从中提取数据。计算进程用完该数据后,再调用Putbuf(emq, sin)过程,将它挂在空缓冲队列emq上。

    (3) 收容输出。计算继承可调用Getbuf(emq),从空缓冲队列emq的队首取得一空缓冲,作为收容输出工作缓冲区hout。当其中装满输出数据后,又调用Putbuf(outq, hout)过程,将它挂在outq末尾。

    (4) 提取输出。输出进程可调用Getbuf(outq)过程,从输出队列的队首取得一装满输出数据的缓冲区,作为提取输出工作缓冲区sout。在数据提取完后,再调用Putbuf(emq, sout)过程,将它挂在空缓冲队列末尾。

8.磁盘存储器的性能和调度

  1. 数据的组织和格式

    磁盘设备可包括一个或多个物理盘片,每个磁盘片分一个或两个存储面(Surface)(如下图(a)),每个盘面上有若干个磁道(Track),磁道之间留有必要的间隙(Gap)。为使处理简单起见,在每条磁道上可存储相同数目的二进制位。这样,磁盘密度即每英寸中所存储的位数,显然是内层磁道的密度较外层磁道的密度高。每条磁道又被从逻辑上划分成若干个扇区(Sectors),软盘大约为8至32个扇区,硬盘则可多达数百个,下图(b)显示了一个磁道分成8个扇区的布局情况。一个扇区称为一个盘块(或数据块),各扇区之间保留一定的间隙(Gap)。

    在这里插入图片描述

    一个物理记录存储在一个扇区上,磁盘上能存储的物理记录块数目是由扇区数、磁道数以及磁盘面数所决定的。为了提高磁盘的存储容量,充分利用磁盘外面磁道的存储能力,现代磁盘不再把内外磁道划分相同数目的扇区,而是利用外层磁道容量较内层磁道大的特点,将磁盘划分成若干条环带,同一环带内的所有磁道具有相同的扇区数。显然外层环带的磁道拥有较内层环带的磁道更多的扇区。为了减少这种磁道和扇区在盘面分布的几何形式变化对驱动程序的影响,大多数现代磁盘都隐藏了这些细节,仅向操作系统提供虚拟几何的磁盘规格,而不是实际的物理几何规格。

    为了在磁盘上存储数据,必须先将磁盘低级格式化。下图示出了一种温盘(温切斯特盘)中一条磁道格式化的情况。其中每条磁道(Track)含有30个固定大小的扇区(Sectors),每个扇区容量为600个字节,其中512个字节存放数据,其余的用于存放控制信息。每个扇区包括两个字段:①标识符字段(ID Field),其中一个字节的SYNCH具有特定的位图像,作为该字段的定界符,利用磁道号(Track)、磁头号(Head #)及扇区号(Sectors #)三者来标识一个扇区;CRC字段用于段校验。②数据字段(Data Field),存放512个字节的数据。值得强调的是,在磁盘一个盘面的不同磁道(Track)、每个磁道的不同扇区(Sectors),以及每个扇区的不同字段(Field)之间,为了简化和方便磁头的辨识,都设置了一个到若干个字节不同长度的间距(Gap,简称间隙)。

    在这里插入图片描述

    在磁盘格式化完成后,一般要对磁盘进行分区。在逻辑上,每个分区就是一个独立的逻辑磁盘。每个分区的起始扇区和大小都记录在磁盘0扇区的主引导记录分区表所包含的分区表中。在这个分区表中必须有一个分区被标记成活动的(即引导块),以保证能够从硬盘引导系统。

  2. 磁盘的类型

    对于磁盘,可以从不同的角度进行分类。最常见的有:将磁盘分成硬盘和软盘、单片盘和多片盘、固定头磁盘和活动头(移动头)磁盘等。下面仅对固定头磁盘和移动头磁盘做介绍。

    (1) 固定头磁盘。这种磁盘在每条磁道上都有一读/写磁头,所有的磁头都被装在一刚性磁臂中。通过这些磁头可访问所有各磁道,并进行并行读/写,有效地提高了磁盘的I/O速度。这种结果主要用于大容量磁盘上。

    (2) 移动头磁盘。每一个盘面仅配有一个磁头,也被装入磁臂中。为能访问该盘面上所有磁道,该磁头必须能够移动以进行寻道。可见,移动磁头仅能以串行方式读/写,致使其I/O速度较慢;但由于其结构简单,故仍广泛应用于中小型磁盘设备中。在微型机上配置的温盘和软盘,都采用移动磁头结构。

  3. 磁盘访问时间

    磁盘设备在工作时以恒定速率旋转。为了读或写,磁头必须能移动到所指定的磁道上,并等待所指定的扇区的开始位置旋转到磁头下,然后再开始读或写数据。故可把对磁盘的访问时间分成以下三部分。

    (1) 寻道时间Ts

    (2) 旋转延迟时间T τ \tau τ

    (3) 传输时间Tt

8.2 早期的磁盘调度算法

  1. 先来先服务(FCFS)
  2. 最短寻道时间优先(SSTF)

8.3 基于扫描的磁盘调度算法

  1. 扫描(SCAN)算法

    SSTF算法的实质是基于优先级的调度算法,因此就可能导致优先级低的进程发生“饥饿”(Starvation)现象。因为只要不断有新进程的请求到达,且其所要访问的磁道与磁头当前所在磁道的距离较近,这种新进程的I/O请求必然优先满足。在对SSTF算法略加修改后,则可防止低优先级进程出现“饥饿”现象。

    扫描(SCAN)算法不仅考虑到欲访问的磁道与当前磁道间的距离,更优先考虑的是磁头当前的移动方向。例如,当磁头正在自里向外移动时,SCAN算法所考虑的下一个访问对象应是其欲访问的磁道既在当前磁道之外,又是距离最近的。这样自里向外地访问,直至再无更外的磁道需要访问时,才将磁臂换向为自外向里移动。这时,同样也是每次选择这样的进程来调度,从而避免了出现“饥饿”现象。由于在这种算法中磁头移动的规律颇似电梯的运行,因而又常称之为电梯调度算法。

  2. 循环扫描(CSCAN)算法

    SCAN算法既能获得较好的寻道性能,又能防止“饥饿”现象,故被广泛用于大、中、小型机器和网络中的磁盘调度。但也存在这样的问题:当磁头刚从里向外移动而越过了某一磁道时,恰好又有一进城请求访问此磁道,这是,该进程必须等待,待磁头继续从里向外,然后再从外向里扫描完处于外面的所有要访问的磁道后,才处理该进程的请求,致使该进程的请求被大大地推迟。为了减少这种延迟,CSCAN算法规定磁头单向移动,例如,只是自里向外移动,当磁头移到最外的磁道并访问后,磁头立即返回到最里的欲访问磁道,亦即将最小磁道号紧接着最大磁道号构成循环,进行循环扫描。采用循环扫描方式后,上述请求进程的请求延迟将从原来的2T减为T+Smax,其中T为由里向外或由外向里单向扫描完要访问的磁道所需的寻道时间,而Smax是将磁头从最外面被访问的磁道直接移到最里面欲访问的磁道的寻道时间(或相反)。

  3. NStepSCAN和FSCAN调度算法

    (1) 在SSTF、SCAN及CSCAN几种调度算法中,都能出现磁臂停留在某处不动的情况,例如,有一个或几个进程对某一磁道有较高的访问频率,即这个(些)进程反复请求对某一磁道的I/O操作,从而垄断了整个磁盘设备。我们把这一线性称为“磁臂粘着”(Armstickiness)。在高密度磁盘上容易出现此情况。N步SCAN算法是将磁盘请求队列分成若干个长度为N的子队列,磁盘调度将按FCFS算法依次处理这些子队列。而每处理一个队列时又是按SCAN算法,对一个队列处理完后,再处理其他队列。当正在处理某子队列时,如果又出现新的磁盘I/O请求,便将新请求进程放入其他队列,这样就可避免出现粘着现象。当N值取得很大时,会使N步扫描法的性能接近于SCAN算法的性能;当N=1时,N步SCAN算法便蜕化为FCFS算法。

    (2) FSCAN算法

    FSCAN算法实质上是N步SCAN算法的简化,即FSCAN只将磁盘请求队列分成两个子队列。一个是由当前所有请求磁盘I/O的进程形成的队列,由磁盘调度按SCAN算法进行处理。另一个是在扫描期间,将新出现的所有请求磁盘I/O的进程放入等待处理的请求队列。这样,所有的新请求都将被推迟到下一次扫描时处理。

猜你喜欢

转载自blog.csdn.net/m0_50833438/article/details/115042779