中山大学操作系统期末复习 吴峻峰
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
期末复习
一、I/O设备缓冲机制
1 引入缓冲的原因
①缓和CPU和IO设备间的速度不匹配矛盾
计算时输出(输入)设备等待CPU,输出(输入)时CPU等待打印机(输入)
②减少CPU中断频率,放宽对CPU中断响应时间的限制
如果从远地终端发来的数据仅用一位缓冲接收,则每次收到一位数据便中断一次CPU,即段时间就要中断CPU,CPU也必须在同样的短时间内作出相应否则数据就被冲掉。
因此需要设置多位缓冲。
③解决数据粒度不匹配问题
若生产者生产的数据粒度比消费者消费的数据粒度小,生产者可以产生多个数据单元数据,直到总和达到消费者进程要求的数据单元大小,消费者再从缓冲区中取出消费;
反之,若生产者生产的数据粒度比消费者消费的数据粒度大,对于生产者每次生产的数据,消费者可分几次从缓冲区取出消费。
④提高CPU与IO设备的并行性
生产者在生产一批数据并将其放入缓冲区后,便可立即进行下一次生产,同时,消费者可以从缓冲区取出数据消费,CPU与打印机可以实现并行工作。
2 缓冲区管理
2.1 单缓冲
在单缓冲情况下,每当用户进程发出一I/O请求时,操作系统便在主存中为之分配一缓冲区,如图a所示。
在块设备输入时,假定从磁盘把一块数据输入到缓冲区的时间为T,OS将该缓冲区中的数据传送到用户区的时间为M,而CPU对这一块数据处理(计算)的时间为C,由于T和C是可以并行的,当T>C时,系统对每一块数据的处理时间为M+T;反之则为M+C,故可把系统对每一块数据的处理时间表示为Max(C, T) + M。
在字符设备输入时,缓冲区用于暂存用户输入的一行数据,在输入期间,用户进程被挂起以等待数据输入完毕;在输出时,用户进程将一行数据输入到缓冲区后继续进行处理,当用户进程已有第二行数据输出时,如果第一行数据尚未被提起完毕,则此时用户进程应阻塞。
2.2 双缓冲
为了加快输入和输出速度,提高设备利用率,人们又引入了双缓冲区机制,也称为缓冲兑换。
在设备输入时,先将数据送入第一缓冲区,装满后便转向第二缓冲区。
此时操作系统可以从第一缓冲区中移出数据,并送入用户进程(如图a)。
接着由CPU对数据
进行计算。
在双缓冲时,系统处理一块数据的时间可以粗略地认为是Max(C,T),如果C<T,可使块设备连续输入;如果C>T,则可使CPU不必等待设备输入。
对于字符设备,若采用行输入方式,则采用双缓冲通常能消除用户的等待时间,即用户在输入完第一行后,在CPU执行第一行中的命令时,用户可继续向第二缓冲区输入下一行数据。
2.3 环形缓冲
环形缓冲区的组织
(1) 多个缓冲区。
在环形缓冲中包括多个缓冲区,其中每个缓冲区的大小相同。
作为
输入的多缓冲区可分为三种类型:用于装输入数据的空缓冲区R、已装满数据的缓冲区G以及计算进程正在使用的现行工作缓冲区C,如图所示
(2) 多个指针。
作为输入的缓冲区可设置三个指针:用于指示计算进程下一个可用缓
冲区G的指针Nextg、指示输入进程下次可用的空缓冲区R的指针Nexti,以及用于指示
计算进程正在使用的缓冲区C的指针Current。
环形缓冲区的使用
(1) Getbuf过程。
当计算进程要使用缓冲区中的数据时,可调用Getbuf过程。
该过程将由指针Nextg所指示的缓冲区提供给进程使用,相应的,须把它改为现行工作缓冲区,并令Current指针指向该缓冲区的第一个单元,同时将Nextg移向下一个G缓冲区。
类似地,每当输入进程要使用空缓冲区来装入数据时,也调用Getbuf过程,由该过程将指
针Nexti所指示的缓冲区提供给输入进程使用,同时将Nexti指针移向下一个R缓冲区。
(2) Releasebuf过程。
当计算进程把C缓冲区中的数据提取完毕时,便调用Releasebuf过程,将缓冲区C释放。
此时,把该缓冲区由当前工作缓冲区C改成空缓冲区R。
类似
的,当输入进程把缓冲区装满时,也应调用Releasebuf过程,将该缓冲区释放,并改为G缓冲区。
进程之间的同步问题
(1) Nexti指针追赶上Nextg指针。
这意味着输入进程输入数据的速度大于计算机进程处
理数据的速度,已把全部可用的空缓冲区装满,再无缓冲区可用。
此时,输入进程应阻塞,直到计算进程把某个缓冲区中的数据全部提取完,使之成为空缓冲区R,并调用Releasebuf过程将它释放时,才将输入进程唤醒。
这种情况被称为系统受计算机限制。
(2) Nextg指针赶上Nexti指针。
这意味着输入数据的速度低于计算进程处理数据的速
度,使全部装有输入数据的缓冲区都被抽空,再无装有数据的缓冲区供计算进程提取数据。
这时,计算进程只能阻塞,直至输入进程又装满某个缓冲区,并调用Releasebuf 过程将它释放时,才去唤醒计算进程。
这种情况被称为系统受I/O限制。
2.4 缓冲池
缓冲池的组成
缓冲池管理着多个缓冲区,每个缓冲区由用于标识和管理的缓冲首部以及用于存放数据的缓冲体两部分组成。
缓冲首部一般包括缓冲区号、设备号、设备上的数据块号、同步信号量以及队列链接指针等。
为了管理上的方便,一般讲缓冲池中具有相同类型的缓冲区链接成一个队列,于是可以形成以下三个队列:
(1) 空白缓冲队列emq。
这是由空缓冲区所链成的队列。
其队首指针F(emq)和队尾指针
L(emq) 分别指向该队列的首缓冲区和尾缓冲区。
(2) 输入队列inq。
这是由装满输入数据的缓冲区所链成的队列。
其中队首指针F(inq)和
队尾指针L(inq)分别指向输入队列的队首和队尾缓冲区。
(3) 输出队列outq。
这是由装满输出数据的缓冲区所链成的队列。
其队首指针F(outq)和
队尾指针L(outq)分别指向该队列的首、尾缓冲区。
除了上述三个队列外,还应具有四种工作缓冲区:用于收容输入数据的工作缓冲区,用于提取输入数据的工作缓冲区,用于收容输出数据的工作缓冲区,以及用于提取输出数据的工作缓冲区。
缓冲区的工作方式
(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)过程,将它挂在空缓冲区队列末尾。
(将输出队列里装满了的放到输出工作缓冲区,然后释放后放回空缓冲区)
二、I/O通道的分类和工作原理
1 字节多路通道
按字节交叉方式工作的通道,含有多个非分配型子通道,数量达几十到数百个,每个子通道连接一个I/O 设备,并控制其IO 操作。
子通道以按时间片轮转的方式共享主通道。
第一个子通道控制其IO 设备完成一个字节交换后立即腾出主通道,供第二个子通道使用,以此类推。
所有子通道轮转一周后,再回到第一个子通道。
只要字节多路通道扫描每个子通道速率足够快,且连接到子通道的设备速率不太高就不会丢失数据。
(不停地扫描各个通道)
不适于连接高速设备
2 数组选择通道
可以连接多台高速设备,但是只含有一个分配型子通道,在一段时间内只能执行一道通道程序,控制一台设备进行数据传送。
导致,如果某台设备占用了该通道后,便一直独占,即使无数据传送,通道被闲置也不允许其它设备使用该通道,直到该设备传送完毕释放该通道。
通道利用率很低,传输速率高。
3 数组多路通道
将数组选择通道传输速率高,和字节多路通道可以使个子通道分时并行操作的优点结合而成的新通道。
含有多个非分配型子通道,有很高的传输速率和通道利用率。
数据传送按数组方式进行,应用于连接多台高中速外围设备。
三、内存空间分配算法
1 单一连续分配
单一连续分区存储管理把整个内存空间的最低端和最高端作为操作系统区,中间作为用户程序区。
在DOS 操作系统中就采用了这种方法,如图所示。
这种存储分配思想将内存分为两个区域:系统区和用户区。
应用程序装入到用户区,可使用用户区全部空间。
单一连续分区的优点是:简单,适用于单用户、单任务的操作系统(比如CP/M 和DOS 操作系统),不需要复杂的硬件支持。
单一连续分区的缺点是:
一个作业运行时要占用整个内存的地址空间,即使很小的程序也是如此,对内存造成了很大的浪费,内存的利用率很低。
分配给用
户作业的空间
0xFFF…
00
2 固定分区分配 为了便于管理整个内存,需建立一个表格来登记和管理整个内存。
在这个表中登记了每一个分区的大小,起始地址和分配状态,如表1和图1所示。
当有作业装入时,系统便可以搜索这个表,找出一个大小合适的分区分配给它。
当程序运行结束时,可以把它所占用的空间再释放回去。
地址重定位可以采用静态地址定位或是动态地址定位的方法。
表1 图1
多道程序环境下,将整个用户空间划分为若干固定大小的区域,每个分区只装入一道作业。
假如内存中有4个内存分区,便允许4个程序并发运行,当有一空闲分区时,再从后备作业队列中选择一个适当大小的作业装入该分区,当该作业结束时,同理。
多道程序下固定分区原理
划分分区:可分为大小相等的分区(不灵活,容易浪费)/大小不等的分区
内存分配:将分区按大小排序,构成分区使用表,有程序要装入时,则顺序的检索该表,找出大小合适的分区分配给用户,若无合适分区,分配失败。
固定分区的优点是:与单一连续分配方法相比,固定分区法的内存利用率提高了;可以支持多道程序;实现简单,开销小。
固定分区的缺点:必须预先能够估计作业要占用多大的内存空间,有时候这是难以做到的;区内碎片造成浪费;分区总数固定,限制了并发执行的程序数目。
3 动态分区分配
1) 空闲存储区表
若采用固定分区法,则作业运行时所需内存一般不会刚好等于某一个分区的大小,因此分区内部的“内零头”被白白浪费了;另一方面,固定分区的分区数在系统启动以后不能任意改变,当系统中运行的作业数大于分区数时,就不可避免地会有一些作业分配不到分区,即使所有作业所需存储空间总和小于内存总和也不行。
可变分区存储管理法并不预先将内存划分成分区,而是等到作业运行需要内存时才向系统申请,从空闲的内存区中挖一块出来,其大小等于作业所需内存的大小,这样就不会产生“内零头”。
管理空闲内存区的数据结构可采用链接法和连续线性表格法。
每一个空闲分区用一个map 结构管理:
struct map{
unsigned m_size; //空闲分区的长度
char * m_addr; //空闲分区的起始地址 操作系统
下界寄存器作业A 作业B 作业C
460K 160K
120K
100K
下界寄存器
260K
};
struct map coremap[N];
图2所示为空闲分区表的初始状态,图3为某一时刻空闲分区表的状态。
图中,m_size 是空闲分区的长度,m_addr 是空闲分区的起始地址。
各个空闲分区按起始地址由低到高的顺序登记在空闲存储区表中,m_size 为0的表项是空白表项,它们集中在表的后部。
图2 空闲分区表的初始状态 图3 某一时刻空闲分区表的状态 2)
.分区分配算法 寻找某个空闲分区,其大小必须大于或等于程序的要求。
若是大于要求,则将该分区分割成两个分区,其中一个分区为要求的大小并标记为“占用”,而另一个分区为余下部分并标记为“空闲”。
分区的先后次序通常是从内存低端到高端。
选择分区的算法有四种:最先适应算法、最佳适应算法、最差适应算法和循环最先适应算法。
2.1 最先适应算法
最先适应算法是将所有的空闲分区按照地址递增的顺序排列,然后按照分区的
先后次序从头开始查找,符合要求的第一个分区就是要找的分区。
该算法的分配和
释放的时间性能较好,较大的空闲分区可以被保留在内存高端。
最先适应算法的优点:①分配简单而且合并相邻的空闲区也比较容易,该算法的实质是尽可能利用存储区低地址的空闲区,而尽量在高地址部分保存较大的空闲区,以便一旦有分配大的空闲区的要求时,容易得到满足。
②在释放内存分区时,如果有相邻的空闲区就进行合并,使其成为一个较大的空闲区。
最先适应算法的缺点:①由于查找总是从表首开始,前面的空闲区被分割得很小时,能满足分配要求的可能性就较小,查找次数就较多。
系统中作业越多,这个问题就越来越严重。
针对这个问题,
对最先适应法稍加改进,就有了循环最先适应法。
②会产生碎片,这些碎片散布在存储器的各处,不能集中使用,因而降低了存储器的利用率。
2.2 循环最先适应算法 相对于最先适应算法,下次适应算法按分区的先后次序,从上次分配的分区开始查找,到最后分区时再回到开头,符合要求的第一个分区就是找到的分区 2.3 最佳适应算法
最佳适应算法的思想是将所有的空闲分区按照其容量递增的顺序排列,当要求
后空闲区释放区
前空闲区(a )(b )(c )(d )
分配一个空白分区时,由小到大进行查找。
最佳适应算法的空闲存储区管理表的组织方法可以采用顺序结构,也可以采用链接结构。
最佳适应算法的优点:①由于算法是在所有大于或者等于要求分配长度的空闲区中挑选一个最小的分区,所以分配后所剩余的空白块会最小。
②平均而言,只要查找一半的表格便能找到最佳适应的空白区。
③如果有一个空白区的容量正好满足要求,则它必被选中。
最佳适应算法的缺点:①由于空闲区是按大小而不是按地址的顺序排列的,因此释放时,要在整个链表上搜索地址相邻的空闲区,合并后又要插入到合适的位置。
②空白区一般不可能恰好满足要求,在分配之后的剩余部分通常非常小,以致小到
无法使用。
2.4 最坏适应算法
将所有的空白分区按容量递减的顺序排列,最前面的最大的空闲分区就是找到的分区。
该算法是取所有空闲区中最大的一块,把剩余的块再变成一个新小一点的空闲区。
算法基本不留下小空闲分区,但较大的空闲分区不会被保留。
最坏适应算法的优点:分配的时候只需查找一次就可以成功,分配的算法很快。
最坏适应算法的缺点:最后剩余的分区会越来越小,无法运行大程序。
3)基于索引的动态分区分配算法
3.1 快速适应算法
该算法又称分类搜索法,是将空闲分区根据其容量大小进行分类,对于每一类具有相同容量的所有空闲分区,单独设立一个空闲分区链表,这样系统中存在多个空闲分区链表。
同时,在内存中设立一张管理索引表,其中的每一个索引表项对应了一种空闲分区类型,并记录了该类型空闲分区链表表头的指针。
空闲分区的分类是根据进程常用的空间大小进行划分的,如2KB、4KB、8KB等,对于其他大小的分区,如7KB这样的空闲区,既可以放在8KB的链表中,也可以放在一个特殊的空闲区链表中。
该算法在搜索可分配的空闲分区时分为两步:第一步是根据进程的长度,从索引表中去寻找到能容纳它的最小空闲区链表;第二步是从链表中取下第一块进行分配即可。
另外该算法在进行空闲分区分配时,不会对任何分区产生分割,所以能保留大的分区,满足对大空间的需求,也不会产生内存碎片。
优点是查找效率高。
该算法的主要缺点在于为了有效合并分区,在分区归还主存时的算法复杂,系统开销较大。
此外,该算法在分配空闲分区时,是以进程为单位的,一个分区只属于一个进程,因此在为进程所分配的一个分区中,或多或少地存在一定的浪费。
这是典型的以空间换时间的做法。
3.2 伙伴系统
伙伴系统规定,无论已分配分区或空闲分区,其大小均为2的k次幂(k为整数,1≤k≤m)。
通常2^m是整个可分配内存的大小(也就是最大分区的大小)。
假设系统的可利用空间容量为2^m个字,则系统开始运行时,整个内存区是一个大小为2^m的空闲分区。
在系统运行过程中,由于不断地划分,将会形成若干个不连续的空闲分区,将这些空闲分区按分区的大小进行分类。
对于具有相同大小的所有空闲分区,单独设立一个空闲分区按分区的大小进行分类。
对于具有相同大小的所有空闲分区,单独设立一个空闲分区双向链表,这样,不同大小的空闲分区形成了k个空闲分区链表。
当需要为进程分配一个长度为n的存储空间时,首先计算一个i值,使2^(i-
1)<n≤2^i,然后在空闲分区大小为2^i的空闲分区链表中查找。
若找到,即把该空
闲分区分配给进程。
否则,表明长度为2^i的空闲分区已经耗尽,则在分区大小为
2^(i+1)的空闲分区链表中寻找。
若存在2^(i+1)的一个空闲分区,则把该空闲分区分
为相等的两个分区,这两个分区成为一对伙伴,其中一个分区用于分配,而把另一
个加入分区大小为2^i的空闲分区链表中。
若大小为2^(i+1)的空闲分区也不存在,
则需要查找大小为2^(i+2)的空闲分区,若找到则也对其进行两次分割:第一次,将
其分割为大小为2^(i+1)的两个分区,一个用于分配,一个加入到大小为2^(i+1)的
空闲分区链表中;第二次,将第一个用于分配的空闲区分割为2^i的两个分区,一
个用于分配,一个加入到大小为2^i的空闲分区链表中。
若仍然找不到,则继续查
找大小为2^(i+3)的空闲分区,以此类推。
由此可见,在最坏的情况下,可能需要对
2^k的空闲分区进行k次分割才能得到所需分区。
与一次分配可能需要进行多次分割一样,一次回收也可能要进行多次合并,如回收大小为2^i的空闲分区时,若事先已存在2^i的空闲分区,则应将其与伙伴分
区合并大小为2^(i+1)的空闲分区,若事先已存在2^(i+1)的空闲分区,又应继续与
其伙伴分区合并为大小为2^(i+2)的空闲分区,以此类推。
3.3 哈希算法
哈希算法就是利用哈希快速查找的优点,以及空闲分区在可利用空闲区表中的分布规律,建立哈希函数,构造一张以空闲分区大小为关键字的哈希表,该表的每
一个表项记录了一个对应的空闲分区链表表头指针。
当进行空闲分区分配时,根据所需空闲分区大小,通过哈希函数计算,即得到在哈希表中的位置,从中得到相应的空闲分区链表,实现最佳分配策略。
4)动态可重定位分区分配
4.1 紧凑:当计算机运行一段时间,内存会被分割成很多小的分区,称之为碎片。
通过移动内存中作业的位置,把原来多个分散的小分区拼接成一个大分区的方法,称为“拼接”或“紧凑”。
4.2 动态重定位:在系统中增设一个重定位寄存器,用来存放程序在内存中的起始
地址。
程序执行时,真正访问的内存地址是相对地址+重定位寄存器中的地址。
4.3 动态重定位分区分配算法:与动态分区分配算法基本相同,差别仅在于增加紧
凑功能。
当该算法不能找到足够大的空闲区域时,若所有碎片大小之和大于需求,便进行紧凑,将紧凑后的大分区分配给用户;若碎片和仍小于需求,则返回分配失败。
四、进程调度算法
1 轮转调度算法(RR)
在轮转法中,系统将所有的就绪进程按FCFS策略排成一个就绪队列。
系统可设置每隔一定时间便产生一个中断,去激活进程调度程序进行调度,把CPU分配给队首进程,并令其执行一个时间片。
当它运行完毕后,又把处理机分配给就绪队列中新的队首进程,也让它执行一个时间片。
这样,就可以保证就绪队列中的所有进程在确定的时间段内,都能获得一个时间片的处理机时间。
在RR调度算法中,应在何时进行进程的切换可分为两种情况:①若一个时间片尚未用完,正在运行的进程便已经完成,就立即激活调度程序,将它从就绪队列中删除,再调度就绪队列中队首的进程运行,并启动一个新的时间。
②在一个时间片用完时,计时器中断处理程序被激活。
如果进程尚未运行完毕,调度程序将把它送往就绪队列的末尾。
2 多级反馈队列
(1)、设置多个就绪队列。
在系统中设置多个就绪队列,并为每个队列赋予不同的优先级。
第一个队列的优先级最高,第二个次之,其余优先级逐个降低。
该算法为不同队列中的进程所赋予的执行时间片的大小也各不相同,在优先级愈高的队列中,其时间片就愈小。
(2)、每个队列都采用FCFS算法。
当新进程进入内存后,首先将它放入第一队列的末尾,按FCFS原则等待调度。
当轮到该进程执行时,如它能在该时间片内完成,便可撤离系统。
否则,即它在一个时间片结束时尚未完成,调度程序将其转入第二队列的末尾等待调度;如果它在第二队列中运行一个时间片后仍未完成,再依次将它放入第三队列。
依次类推。
当进程最后被降到第n队列后,在第n队列中便采取按RR方式运行。
(3)、按队列优先级调度。
调度程序首先调度最高优先级队列中的诸进程运行,仅当第一队列空闲时才调度第二队列中的进程运行;换言之,仅当第1~(i-1)所有队列均为空时,才会调度第i队列中的进程运行。
如果处理机正在第i队列中为某进程服务时又有新进程进入任一优先级较高的队伍,此时须立即把正在运行的进程放回到第i队列的末尾,而把处理机分配给新到的高优先级进程。
3 优先级调度算法
优先级进程调度算法,是把处理机分配给就绪队列中优先级最高的进程。
这时,又可进一步把该算法分成如下两种。
(1) 非抢占式优先级调度算法。
一旦把处理机分配给就绪队列中优先级最高的进程
之后,该进程便一直持续下去直至完成或因某事件而放弃处理机为止,系统方能再次分配处理机给下一优先级最高的进程。
(2) 抢占式优先级调度算法。
把处理机分配给优先级最高的进程,但若在其执行期
间出现优先级更高的进程,则立即切换进程,将处理机分配给新的最高优先级进程。
常用于对实时性要求较高的系统中。
优先级的类型
1) 静态优先级
静态优先级是在创建进程时确定的,在进程的整个运行期间保持不变。
优先级是利用某一范围内的一个整数来表示的,例如0~255中的某一整数,又把该整数称为优先数。
确定进程优先级大小的依据有如下三个:
①进程类型。
通常系统进程(如接收进程、兑换进程)优先级高于一般用户进程优
先级。
②进程对资源的需求。
对资源要求少的进程应赋予较高优先级。
③用户要求。
根据进程的紧迫程度和用户付费多少确定优先级。
优点:简单易行,系统开销小。
缺点:不够精确,可能出现优先级低的进程长期没有被调度的情况。
2) 动态优先级。