一、设备无关性软件
实现设备无关:采用分层思想,逐层抽象,Linux系统采用设备文件统一管理硬件设备,从而将硬件设备的特性和管理细节对用户隐藏起来,实现了用户程序与设备无关性,用户是通过文件系统来访问设备,所有设备都作为特别文件
1、什么是设备无关的I/O软件
用户程序的设备无关性:是指用户程序不直接使用物理设备名,而只是使用逻辑设备名,系统在实际执行时将逻辑设备名转换为某个具体的物理设备名,实施I/O操作
I/O软件的设备无关性:是指除了直接与设备打交道的底层软件,其他软件部分并不依赖于硬件,I/O软件独立于设备,就可以提高设备管理软件的设计效率
逻辑设备是抽象的设备名,并不指定具体设备,设备分配灵活,可实现I/O重定向
(逻辑设备表LUT将应用程序中使用的逻辑设备映射为物理设备名,并提供该设备驱动程序的入口地址)
2、与设备无关软件的功能层次
与设备无关的软件是I/O系统的最高层软件(之下是设备的驱动程序),与设备无关的软件执行常用的I/O功能,包括:
- 设备驱动的统一接口
- 缓冲管理:缓和CPU和I/O设备运行速率的矛盾
- 差错控制:I/O操作绝大数错误都与设备有关
- 对独立设备的分配与回收:系统设备必须由系统统一分配,不允许进程自行使用
- 独立于设备的逻辑数据块:向高层软件提供大小统一的逻辑数据块(隐藏不同设备属性的差异)
3、设备分配及其数据结构
系统设备供所有进程共享,为防止多个进程对系统资源的无序竞争,规定系统设备不允许用户自行使用,必须由系统统一分配,每当进程向系统提出I/O请求时,设备分配程序按照一定的策略把设备分配给请求进程,还应分配相应的控制器和通道
一个系统中可以有多个通道,一个通道可以控制多个控制器,一个控制器可以控制多个设备
3.1 设备控制表DCT
3.2 控制器控制表COCT
3.3 通道控制表CHCT
3.4 系统设备表SDT
SDT记录的是系统中的全部设备,每个设备占一个表目,当用户根据设备名请求某个设备时,OS可以根据SDT找到用户指定的设备
3.5 设备分配步骤
进行设备分配时,要借助设备控制表DCT、控制器控制表COCT、通道控制表CHCT、系统设备表SDT等数据结构:
1、分配设备:根据进程请求的物理设备名查找SDT,用户在编程时需要用物理设备名作为系统调用参数,根据用户提供的物理设备名查找到对应的表项就可以找到该设备对应的设备控制器(DCT),根据查找到的DCT,判断设备当前状态,空闲则将设备分配给进程,忙碌则将进程的PCB挂到设备等待队列中,直到设备空闲,把设备分配给进程,并把进程唤醒
2、分配控制器:系统会根据DCT找到对应的控制器控制表(COCT),首先判断控制器当前状态,空闲则将控制器分配给进程
3、分配通道:系统根据COCT中指向通道表的指针找到通道控制表(CHCT),首先判断通道当前状态,空闲则将通道分配给进程
三者都分配成功后,便可启动I/O设备进行数据传送
上述设备分配过程有3个缺点:
- 用户编程时必须使用物理设备名,底层细节对用户不透明,不方便编程
- 如果换了一个物理设备,即使是同类型设备,程序也无法运行
- 如果进程请求的物理设备正在忙碌,即使系统还有同类型设备,进程也必须阻塞等待
改进方法:建立逻辑设备名与物理设备名的映射机制,用户编程时只需提供逻辑设备名,为实现与设备的无关性,当应用程序请求使用I/O设备时,应当用逻辑设备名,但系统只识别物理设备名,在系统中需配置一张逻辑设备表,将逻辑设备映射为物理设备,根据进程请求的逻辑设备名查找SDT,SDT中就有一个字段记录了设备类型,因此OS可以通过用户提供的逻辑设备名依次查找SDT,在同类型设备中选择一个空闲设备进行分配
2、用户层I/O软件
2.1 系统调用与库函数的关系
大部分I/O软件都在操作系统内部,小部分在用户层,包括与用户程序链接在一起的库函数,以及完全运行于内核之外的假脱机系统
系统调用通常由库函数封装,供用户使用,封装函数只是将系统调用所用的参数放在合适位置,然后执行访管指令来陷入内核,再由内核函数实现真正的I/O操作
2.2 假脱机技术(spooling)系统
定义:SPOOLing是外部设备同时联机操作,又称为假脱机输入/输出操作,是操作系统中采用的一项将独占设备改造成共享设备的技术
2.2.1 为什么要引入假脱机技术?
为了缓和CPU的高速和I/O设备低速之间的矛盾,引入脱机输入/输出技术,该技术是利用专门的外围控制机,将低速I/O设备上的数据传送到高速磁盘上(或者相反)
假脱机技术(spooling)是用软件的方法来模拟脱机技术,由输入井和输出井、输入进程和输出进程、以及输入缓冲区和输出缓冲区组成
- 输入井和输出井是用于模拟脱机技术中的磁带
- 输入进程和输出进程用于模拟脱机技术中的外围控制机
- 输入缓冲区暂存从输入设备输入的数据,之后再转存到输入井中
- 输出缓冲区暂存从输出井传送的数据,之后在传送到输出设备上
2.2.2 共享打印机
当用户进程请求打印进程时,spooling系统同意为它打印输出,但不真正立即把打印机分配给该用户进程,而为它做两件事:
- 在磁盘输出井中为进程申请一个空闲磁盘块,之后假脱机管理进程会将进程要打印的数据送入刚申请的空闲磁盘块中
- 为用户进程申请一张空白的打印请求表,并将用户的打印请求填入表中,再将该表挂到假脱机文件队列上
当打印机空闲时,输出进程会从文件队列中的队头取出一张打印请求表,并根据表中的要求将要打印的数据从输出井传送到输出缓冲区,再输出到打印机打印,用这种方式可依次处理完全部的打印任务
2.2.3 SPOOLing系统的特点
spooling除了是一种速度匹配技术外,也是一种虚拟设备技术,有三个特点:
- 提高了输入输出速度:spooling技术引入了输入井和输出井,使输入进程、用户进程和输出进程同时工作
- 将独占设备改造为共享设备:spooling技术把所有用户进程的输出数据都送入输出井,由输出进程完成打印工作,而输出井在磁盘上为共享设备
- 实现了虚拟设备功能:spooling技术实现了多个用户进程共同使用打印机这种独占设备的情况,从而实现了把一个设备当成多个设备来使用(虚拟设备)
2.3 守护进程
守护进程:实际上是后台服务进程,Linux有很多系统服务,大多数服务都是通过守护进程实现的,同时守护进程还能完成许多系统任务
例如在Linux中为打印机建立了一个守护进程,在Linux下也采用假脱机打印方法,当用户需要打印一个文件时,该文件并不直接送到打印机,而是送到spool目录下,然后由一个负责打印的后台进程把这些数据送入打印机,Linux为每个打印机都定义了一个打印缓冲区,打印机守护进程经常扫描打印缓冲区,以查看有无新文件,如果存在就按先进先出的顺序打印缓冲区中的文件
3、缓冲区管理
缓冲区是一个存储区,可以由专门的寄存器(成本较高)组成,也可以由内存作为缓冲区
CPU可以把要输出的数据快速的放入缓冲区,之后就可以做别的事,慢速的I/O设备可以慢慢的从缓冲区取走数据
3.1 缓冲区的引入
- 缓和CPU和I/O设备之间速度不匹配的矛盾
- 减少对CPU的中断频率,放宽对CPU中断响应的时间限制
- 解决数据粒度不匹配的问题
- 提高CPU和I/O设备的并行性
3.2 单缓冲区
采用单缓冲策略,OS会在主存中为其分配一个缓冲区,缓冲区的特性是当缓冲区数据非空时,不能往缓冲区存入数据,只能从缓冲区把数据取出来,当缓冲区为空时,可以往缓冲区存入数据,但必须把缓冲区充满以后才能从缓冲区把数据传出
采用单缓冲策略,处理一块数据平均耗时max(C, T) + M(C为CPU处理时间,T为输入时间,M为传送时间)
3.3 双缓冲
采用双缓冲策略,OS会在主存中为其分配两个缓冲区,进一步加快了输入和输出速度,从设备输入时,数据送入第一缓冲区,装满后转向第二缓冲区,然后进行读出操作,OS从第一缓冲区移除数据,送入用户进程,再有CPU进行数据计算,两个缓冲区可以实现连续处理,无需等待对方
采用双缓冲策略,平均耗时为max(T, C + M)
实际上,双缓冲还适合双向通讯,实现两台机器之间的通讯时,仅配置了单缓冲只能实现单方向的数据传送,为了实现数据的双向传送,必须在两台机器中都设置两个缓冲区,一个用于发送缓冲区,另一个用于接收缓冲区
3.4 环形缓冲区
若输入输出速度相差甚远,双缓冲效果不理想,此时引入环形缓冲,在缓冲区中包含多个缓冲区,其每个缓冲区的大小相同,橙色表示已充满数据的缓冲区,蓝色表示空缓冲区,当需要向缓冲区冲入数据时,只要找到in指针指向的空缓冲区冲入数据,然后再将in指针指向下一个空缓冲区;当需要取出满缓冲区的内容时,找到out指针指向的满缓冲,读完数据后将指针指向下一个满缓冲区
3.5 缓冲池
缓冲池由系统中的公用缓冲区组成
- 按使用情况可分为:空缓冲区队列、输入数据缓冲队列(从设备发送给内存的数据)、输出数据缓冲队列(从内存发送给设备的数据)
- 按实际运算扮演功能:用于收容输入数据的工作缓冲区hin、提取输入数据的工作缓冲区sin、收容输出数据的工作缓冲区hout、提取输出数据的工作缓冲区sout
四种工作方式:
- 当输入数据请求输入数据时,就会从空缓冲队列取出队头的缓冲区,把它作为hin,充满数据后将缓冲区挂到输入队列的队尾
- 计算进程想取得一块数据,从输入队列队头取得一块满输入缓冲区,作为sin,缓冲区的数据被读空后挂到空缓冲区队列
- 计算进程将准备好的数据充入缓冲区,从空缓冲队列中队头的缓冲区,作为hout,充满数据后将缓冲区挂到输出队列的队尾
- 输出进程请求输出数据,从输出队列取出队头缓冲区,作为sout,数据被读空后挂到空缓冲区队列
可以调用Getbuf()和Putbuf()函数完成:Getbuf从缓冲区队列取出一个缓冲区,Putbuf函数完成将缓冲区插入对应缓冲队列的过程,为使多个进程能互斥和同步的访问缓冲池队列,可分别为每一队列设置一个互斥信号量MS和资源信号量RS
2、磁盘存储器的性能和调度
磁盘存取的速度相当慢,容量大价格便宜
2.1 磁盘的结构
2.1.1 如何在磁盘上读/写数据
磁盘表面由一些磁性物质组成,用于记录二进制数据,磁盘表面有多个磁道,划分为多个扇区,每个扇区就是一个磁盘块,数据量相同,磁盘读写数据需要借助磁头,将磁头移动到想要读或者写的扇区所在的磁道,磁盘会旋转,让目标扇区从磁头下面划过,完成对扇区的读写操作
磁盘由多个盘片组成,每个盘面都对应一个磁头,所有磁头都连在同一个磁臂上,磁臂可以沿盘面做径向运动,从而带动磁头达到不同的磁道,不同盘面上的同半径磁道组成了柱面
2.1.2 磁盘的物理地址
可以使用(柱面号、盘面号、扇区号)来定位任何一个磁盘块,文件就是存放在离散的盘块中,磁盘工作时就是根据该地址读取一个块,磁盘寻址磁臂带动磁头径向移动,再通过磁盘自旋定位到访问的扇区
磁盘分类:活动头磁盘、固定头磁盘
2.2 磁盘调度算法
一次磁盘读写操作需要的时间
寻道时间Ts = s + m * n:需要将磁头移动到指定磁道所花费的时间,分两步:
- 启动磁头臂所花费的时间s
- 移动磁头所花费的时间m(每跨越一个磁道时间)*n(跨越磁道数)
延迟时间TR = 1 / (2r):通过旋转使磁头定位到目标扇区所需要的时间,平均需要转半圈
传输时间TR = b / (rN):磁盘读写所经历的时间,假设磁盘转速为r,读写字节数为b,每个磁盘上的字节数为N
延迟时间和传输时间都是与磁盘转速线性相关的,而转速又是磁盘的固有属性,无法通过OS程序优化延迟时间和传输时间,只能优化寻道时间,磁盘调度算法的主要目标是减少请求队列中的平均柱面定位时间,目前常用的磁盘调度算法有:先来先服务、最短寻道时间优先、扫描算法、循环扫描算法
2.2.1 先来先服务(FCFS)调度算法
算法思想:根据进程请求访问磁盘的先后顺序进行调度
优点:公平、简单
缺点:FCFS在性能上很差,寻道时间长
2.2.2 最短寻道时间优先(SSTF)调度算法
算法思想:优先处理的磁道是与当前磁头最近的磁道
优点:该策略有较低的平均响应时间
缺点:对用户的服务请求的响应机会不是均等的,可能会有进程处于饥饿状态(磁头有可能在一个小的区域来回移动)
2.2.3 扫描(SCAN)调度算法
算法思想:磁头只有移动到请求最外侧磁道或者最内侧磁道才可以反向移动,也称为电梯算法
优点:不会产生饥饿现象
缺点:响应频率不平均
2.2.4 循环扫描(C-SCAN)调度算法
算法思想:规定只有磁头朝某个特定方向移动时才处理磁道请求,而返回时直接快速移动到最靠边缘的并且需要访问的磁道上而不处理任何请求
优点:响应频率很平均
缺点:平均寻道时间长