考研408——机组OS
文章目录
- 计算机组成原理
- 机器字长、指令字长、存储字长
- float类型浮点数
- 指令格式
- CPU的不同类型
- 指令周期
- 指令周期、工作周期、机器周期、时钟周期之间的关系
- 指令流水线
- 指令流水线的基本结构
- 普通流水线、超标量流水线、超流水线、超长指令字对比
- 中断
- 中断的类型
- 中断的处理流程
- DMA
- DMA的传送方式
- 操作系统
- 进程同步
- 同步互斥机制的设计原则
- 死锁
- 死锁产生的必要条件
- 内存管理策略
- 软链接与硬链接
- 硬链接
- 软链接
- 打开文件表
- 进程文件打开表
- 系统打开文件表
- 文件的逻辑结构
- 什么是文件的逻辑结构?
- 文件的逻辑结构有哪些?
- 1. 无结构文件
- 2. 有结构文件
- 按照记录是否等长分类
- 按照记录的组织形式分类
- (1)顺序文件
- (2)索引文件
- 为什么要引入索引文件?
- 索引文件是如何解决上述问题的?
- 索引文件结构的缺点
- (3)索引顺序文件
- 为什么要引入索引顺序文件结构?
- 索引顺序文件结构的缺点
- (4)直接文件、散列文件
- 总结
- 文件的物理结构
- 什么是文件的物理结构?
- 文件的物理结构有哪些?
- (1)连续分配
- (2)链接分配——隐式链接方案
- 为什么要引入链接分配?
- 隐式链接分配方案如何解决上述问题?
- 隐式链接分配方案的缺点
- (2)链接分配——显示链接方案
- 为什么要引入显示链接方案
- 显示链接方案的优缺点
- (3)索引分配——单级索引分配
- (3)索引分配——多级索引分配
- (3)索引分配——混合索引分配
- 设备独立性软件
- 什么是设备独立性软件?设备独立性软件是干啥的?
- 设备独立性软件的核心作用
- 设备独立性软件的关键特点
计算机组成原理
机器字长、指令字长、存储字长
1. 机器字长(Machine Word Length)
- 定义:指计算机CPU一次能直接处理的二进制数据的位数,通常与CPU的寄存器位数、运算器位数一致。
2. 指令字长(Instruction Word Length)
- 定义:一条指令所包含的二进制位数,即指令的编码长度。
3. 存储字长(Memory Word Length)
- 定义:存储器(如内存)一次读写操作所能的二进制位数,即存储单元的宽度。
float类型浮点数
注意:阶码的偏置值是127!
指令格式
操作码+地址码+寻址方式
CPU的不同类型
- 单周期 CPU:全部操作在一个“大时钟周期”内完成,每条指令只占用 1 个时钟周期 → CPI = 1。
- 多周期 CPU:把取指、译码、执行等分解到多个时钟周期,不同指令用的周期数不同,平均 CPI > 1。
- 基本流水线 CPU:理想情况下流水段数为 k,装满后每拍流出 1 条指令 → CPI = 1。
- 超标量流水线 CPU:一次可发射 n(n > 1) 条指令,理想 CPI = 1/n < 1
指令周期

指令周期、工作周期、机器周期、时钟周期之间的关系
一个指令周期,包括:取指、间址、执行、中断四个工作周期
一个工作周期内有若干的机器周期
一个机器周期内有若干个时钟周期
CPU 工作周期及其访存目的
| CPU 工作周期 | 访存目的 |
|---|---|
| 取指周期 | 取指令 |
| 间址周期 | 获得操作数的有效地址 |
| 执行周期 | 取操作数、存操作数 |
| 中断周期 | 保存断点、执行中断服务程序、恢复断点 |
CPU中其余各周期的定义
| 周期名称 | 特点 |
|---|---|
| 指令周期 | 从将这个指令从内存中取出来开始,到这个指令执行完成,所需要的时间 |
| 取指周期 | 从内存中读出一个指令字的最短时间 |
| 存取时间 | 发起一次内存读/写到完成读/写的时间 |
| 存取周期 | 连续完成两次内存读/写操作,之间的“最短”时间间隔,通常存取周期大于存取时间,因为内存有冷却时间 |
| 机器周期 | 执行指令周期当中一步相对完整的操作所用的时间,因为 CPU 速度比主存快,因此机器周期一般设置为存取周期 |
| 时钟周期 | 时钟周期是主频的倒数,是 CPU 中最小的时间单位,时钟周期以相邻状态单元间组合逻辑电路的最大延迟为基准确定 |
指令流水线
指令流水线的基本结构

- 取指令(IF):负责将指令从指令存储器中取出,通常在IF段结束时,PC的值就会自动 + “1”。
- 指令译码、取操作数(ID):控制器对指令字中的操作码进行译码,同时从通用寄存器中取出操作数。
- 执行或访存地址运算(EX):执行计算或计算地址。
- 存储器访问(MEM):对主存进行读或写操作。
- 结果写回(WB):将指令执行的结果写回通用寄存器中。
普通流水线、超标量流水线、超流水线、超长指令字对比

中断
中断的类型
①根据异常事件来源的不同,可分为内部异常和外部中断
- 内部异常(Exception): 通常是指CPU内部引起的异常事件,也被称为内部中断或者软件中断, 异常可进一步划分为
- 故障(Fault)
- 自陷(Trap)
- 终止(Abort)
- 外部中断(Interrupt):外部设备向CPU发出的中断请求,请求CPU先停下来手里的活,帮忙先处理下比较紧急的外部中断,处理好之后再回去接着忙自己的事
内部中断中,故障和终止有啥区别?
故障是指令级别的错误,操作系统层面就能处理,不用重启系统
终止是计算机硬件级别的错误,此时肯定系统就崩了,需要修复后重启系统
②按中断请求是否可被屏蔽分类,可分为可屏蔽中断和非屏蔽中断。
③按能否直接提供中断服务地址分类,可分为向量中断和非向量中断。
(1) 向量中断:向量中断是指中断事件可以提供中断服务入口地址的中断。
(2) 非向量中断:非向量中断是指中断事件不能直接提供中断服务程序入口地址的中断。
④ 按中断过程能否被打断分类,可分为单重中断和多重中断。
(1) 单重中断:单重中断指 CPU 执行中断服务程序过程中不能被其他中断请求打断的中断。
(2) 多重中断:多重中断指 CPU 执行中断服务程序过程中可以去响应更高优先级的中断请求的中断。又称为中断嵌套
中断的处理流程
CPU在某个时刻收到了来自中断源的中断请求,在当前指令周期结束之后,开始进行中断响应
中断响应第一步:执行中断隐指令
首先我们要执行中断隐指令
- 关中断
- 保存断点
- 将中断处理程序的起始地址装入PC
中断响应第二步:保存现场和中断屏蔽字
紧接着我们就去执行对应的中断处理程序了。那是不是说我直接就执行了呢?也不是,在执行完中断隐指令之后,执行具体的中断处理程序之前,我们还要做一件事情,那就是——保存现场和中断屏蔽字
(如果是多重中断,这里要开中断)
中断响应第三步:执行具体中断程序
(如果是多重中断,这里要关中断)
中断响应第四步:恢复现场和中断屏蔽字
中断响应第五步:开中断
中断响应第六步:中断返回
上面我们说的是单重中断的处理流程,如果系统支持多重中断,那么在保存现场和中断屏蔽字之后要开中断,恢复现场和中断屏蔽字之前要关中断
DMA
DMA的传送方式
我们知道,DMA控制器和CPU都与主存直接相连,都能对主存进行存取操作。但是一般的主存并不能同时支持这俩同时访存,因此我们就需要想办法让他们错开访问
方法一:DMA优先策略
最直接的思路就是,只要DMA控制器发信号(IO设备发送了DMA请求),CPU在当前工作周期结束之后,立即停止访存,把内存让给DMA控制器。等DMA传输结束之后,DMA控制器再给CPU发送一个“我传完了”的信号,CPU再重新开始访存

但是这样的思路有一个很大的缺陷,那就是一旦CPU把主存让给了DMA控制器,在接下来的很长一段时间内,CPU都不能访存了。一旦CPU执行了某条需要访存的指令,那就会陷入阻塞,一直等到DMA把主存还给CPU。在这段时间内,CPU啥都干不了
方法二:交替访存
将CPU的工作周期分两半,前半段允许CPU访存,后半段允许DMA访存

这种方法最大的缺点就是增加了一个工作周期的时长,从而就会使得CPU每秒执行的指令数减半,相当于直接把计算机的运行效率砍半
交替访存比较适合于CPU工作周期比主存存取周期长的情况。这种情况下,CPU的工作周期就大致等于访存时间+运算时间。CPU运算的时候用不到主存,这时候我们就把主存让给DMA控制器。CPU访存的时候,再把控制权拿回来,这样就不会被卡住
方法三:周期窃取
这个思路就是结合了一下方法1和方法2。首先看方法1,它最大的缺点就在于:让权给DMA之后,CPU阻塞的时间太长了。既然如此,那我就不让CPU让那么长时间,一次就让给DMA控制器1到2个周期,时间到了立马收回。有的人就说了,DMA要传的数据那么多,你时间给少了传不完咋办?很简单,一次传不完,那就让DMA控制器多借几次。
总结一下,在周期窃取策略中,我们依然秉持着DMA优先的策略,一旦DMA控制器发起了DMA请求,CPU就要尽快把主存让给DMA:
- 如果CPU在收到DMA请求时没有访存,那没啥好讲的,立即让权
- 如果CPU在收到DMA请求时正在访存,那就等CPU这个存取周期结束之后再让权
- 如果CPU在收到DMA请求时正在发起访存(想要访问,还没开始访问),那CPU就主动退让,把控制权交给DMA控制器
主存让给DMA控制器之后,DMA控制器只能传一到两个访存周期,时间一到立马就还给CPU。如果没传完,就下次再发起DMA请求

操作系统
进程同步
同步互斥机制的设计原则
- 空闲让进
- 忙则等待
- 有限等待
- 让权等待
死锁
死锁产生的必要条件
- 互斥条件
- 请求和保持条件
- 不可剥夺条件
- 循环等待条件
内存管理策略
软链接与硬链接
硬链接
创建硬链接时,系统只需在指定目录下新增一个目录项,让该目录项指向目标文件的 inode,并将 inode 的链接计数(硬链接数量)加 1,这就完成了一个文件的硬链接的创建
创建出的硬链接,除了名字和完整路径可以和源文件不同,其余所有属性都和源文件相同,并且会实时同步(本质就是他们指向同一个innode)
软链接
软链接就是创建一个新文件,把目标文件的完整路径作为这个文件的内容
打开文件表
进程文件打开表
就是你记的那个fd_array,每个进程都独立私有一张进程打开文件表。表项的内容主要是进程的私有数据:
- 指向系统文件打开表对应表项的指针
- 进程对这个文件的读写指针
- 进程对这个文件的访问权限
系统打开文件表
除了进程打开文件表中的那些私有属性之外,其他的全局属性都会记录在系统打开文件表中,每个打开的文件通过innode号作为它的唯一标识
文件的逻辑结构
什么是文件的逻辑结构?
啥叫文件的逻辑结构呢?其实很好理解,就是在用户的视角下,看到的文件结构。啥叫用户视角下看到的文件结构?难道用户看到的文件结构不是真正的文件结构吗?没错,确实不是,那为啥呢?
这主要是因为,为了实现高效的存储(为了在有限的空间内装入尽可能多的文件),工程师们肯定会设计一些特殊机制。而这些特殊机制在用户层面是不好理解的,如果把原原本本的结构展现给用户,这样就会增加用户的理解成本,不利于产品的推广。为了使产品的用户尽可能的多,我们肯定是要想尽一切办法,让用户使用计算机变得很简单。文件结构也是一样,我们要对实际的文件结构进行封装,使得用户看到的文件结构是容易理解的。
文件的逻辑结构有哪些?
按逻辑结构,文件可划分为无结构文件和有结构文件两大类。
1. 无结构文件
无结构文件是最简单的文件组织形式,它是由字符流构成的文件,所以又称流式文件,其长度以字节为单位。对流式文件的访问,通过读/写指针来指出下一个要访问的字节。在系统中运行的大量源程序、可执行文件、库函数等,这些文件就是无结构文件。由于无结构文件没有结构,因而对其中具体内容的访问只能通过穷举搜索的方式,因此这种文件形式对很多应用不适用。
2. 有结构文件
按照记录是否等长分类
有结构文件是指由一个以上的记录构成的文件,所以又称记录式文件。各记录由相同或不同数目的数据项组成,根据有结构文件中各记录的长度是否相等,可分为定长记录和变长记录两种类型
- (1)定长记录:文件中所有记录的长度都是相同的,各数据项都在记录中的相同位置,具有相同的长度。检索记录的速度快,方便用户对文件进行处理,广泛用于数据处理中。
- (2)变长记录:文件中各记录的长度不一定相同,原因可能是记录中所包含的数据项数目不同,也可能是数据项本身的长度不定。检索记录只能顺序查找,速度慢。
按照记录的组织形式分类
有结构文件按记录的组织形式可以分为顺序文件、索引文件、索引顺序文件。
(1)顺序文件
顾名思义,顺序文件中的记录是一个接一个地顺序排列的,顺序文件的记录既可以是定长记录,也可以是变长记录。顺序文件中记录的排列有两种结构:
- 串结构,各记录之间的顺序与关键字无关,通常是按存入的先后时间进行排列,检索时必须从头开始顺序依次查找,比较费时;
- 顺序结构,所有记录按关键字顺序排列,对于定长记录的顺序文件,检索时可采用折半查找,效率较高。
在对记录进行批量操作,即每次要读或写一大批记录时,顺序文件的效率是所有逻辑文件中最高的。此外,对于顺序存储设备(如磁带),也只有顺序文件才能被存储并能有效地工作。在经常需要查找、修改、增加或删除单个记录的场合,顺序文件的性能较差。
(2)索引文件
为什么要引入索引文件?
有人看到这可能会想,我看你前面说的顺序文件结构,不是蛮好的吗?为啥又要引入这个索引文件呢?引入索引文件,肯定是为了解决顺序文件结构存在的问题。那顺序文件结构存在啥问题呢?最主要的问题就是:变长记录的顺序文件,是不能支持随机访问的
对于定长记录的顺序文件,要查找第iii条记录,可直接根据下式计算得到第iii条记录相对于第1条记录的地址:Ai=i×LA_i = i \times LAi=i×L。然而,对于变长记录的顺序文件,要查找第iii条记录,必须顺序地查找前i−1i-1i−1条记录,以获得相应记录的长度LLL,进而按下式计算出第iii条记录的地址:
Ai=∑i=0i−1Li+1A_i = \sum_{i=0}^{i-1} L_i + 1Ai=∑i=0i−1Li+1
索引文件是如何解决上述问题的?
前面我们说到,变长记录的顺序文件只能顺序查找,效率很低。为了提高变长记录文件的查找效率,工程师们就设计出了索引文件结构。
所谓的索引文件结构,其实就是在顺序文件结构的基础上,多建立一张索引表(如下图所示)

虽然文件中各个记录的长度不相同,但是它们在索引表中表项的长度都是相同的。引入索引表之后,我们想要找到某个文件,就再也不用从头挨个找,而是只需要在索引表中进行小范围查找即可。又因为索引表中各表项是按照关键字进行有序排列的,因此我们在索引表中也不用顺序查找,直接折半查找即可,找到对应表项之后,按照里面的指针,就能直接找到对应的记录。
到此为止,引入索引表之后,我们再想查文件中的某条记录,就不用对文件进行顺序查找了,而是只需要对索引表进行折半查找。这就大大提高了查找效率
索引表按关键字排序,因此其本身也是一个定长记录的顺序文件。引入索引表之后,就将对变长记录顺序文件的顺序检索,转变成了对定长记录索引文件的随机检索,从而加快了记录的检索速度。
索引文件结构的缺点
索引文件结构最大的缺点就是,它引入的那个索引表是额外占空间的,相当于是牺牲了一些存储空间,换取了更高的查找效率
(3)索引顺序文件
为什么要引入索引顺序文件结构?
看到这里肯定有人还会问,索引文件结构这么好,为啥还要引入索引顺序文件结构呢?同样的,引入索引顺序文件结构的目的,肯定是为了解决索引文件结构中存在的问题。那这个问题是啥呢?是前面提到的索引表额外占空间吗?不是的,前面那个问题太根本了,真没办法优化。但是一些小问题,还是能继续优化的,比如:
如果我们有10000条索引表项,你现在要通过折半查找的方法查找其中的一条,那么查找的时间复杂度就是O(log n),即100次。有的人说100次还是有点多,查起来其实还是蛮费劲的,为了进一步的减少查找次数,我们就引入了索引顺序文件结构。所谓的索引顺序文件结构,其实就是多级索引结构。试想一下,如果我采用了二级索引结构,那么我二级索引目录就只有100个表项,1级索引目录也只有100个表项,那么查找的次数就变成了2∗log100=202 *log 100=202∗log100=20次
索引顺序文件结构的缺点
很明显,多级索引结构在进一步提高查找效率的同时,其牺牲的存储空间也变多了
(4)直接文件、散列文件
将文件中的某些关键字(比如innode编号)与文件的物理地址建立映射,生成对应的哈希函数。此后我们就能通过hash(innode)直接得到文件对应的物理地址了
总结
到这里大家其实已经能看出来了,所谓的文件逻辑结构,其实是和查找算法息息相关的。设计多种多样的文件逻辑结构,本质上就是为了方便文件中记录的查找
文件的物理结构
什么是文件的物理结构?
这个应该比较好理解,就是文件具体在存储器中是咋存的。
文件的物理结构有哪些?
(1)连续分配
这个分配规则是我们很容易想到的,假如说一个文件的大小占两个磁盘块,那我在实际存放的时候,就把这个文件放在磁盘的两个连续磁盘块中。即:逻辑上相邻的数据,在实际存储时也是相邻的
放好之后,在磁盘的目录块中记录这个文件的起始磁盘块号,以及这个文件总共占几个磁盘块。
连续分配的优点:
- 直观,容易理解,由于有目录块,可以支持随机访问
连续分配的缺点:
- 容易产生很多无法利用的外部小碎片
- 无法满足文件动态增长的需求
- 删除一个文件时,需要整体移动后面的所有文件
(2)链接分配——隐式链接方案
为什么要引入链接分配?
肯定还是因为前面的连续分配存在一些问题。
- 外部碎片问题会导致磁盘的空间利用率变低,文件不支持动态增长则没办法满足现在大部分文件的需求。这俩都是很要命的问题
- 为了解决这俩问题,工程师们才设计出了链接分配的方案
隐式链接分配方案如何解决上述问题?
假如说一个文件的大小是3个磁盘块,在连接分配方案中,我们不要求逻辑上相邻的磁盘块在物理上也必须相邻,而仅仅要求:每个磁盘块的最后一小块位置不存数据,而是存一个指针,指向与其逻辑上相邻的下一个磁盘块。这样虽然这些磁盘块物理上不相邻,但我们却可以通过指针将它们串起来。
在磁盘的目录块中,如果采用隐式链接分配方案,那文件的目录项中只需要记录这个文件第一个磁盘块和最后一个磁盘块的指针
采用隐式链接分配方案,逻辑上相邻的磁盘块物理上可以不再相邻,从而使得我们可以见缝插针地为文件拓展磁盘块,上面的两个问题就都解决了
隐式链接分配方案的缺点
-
隐式链接分配方案解决了外部碎片和文件动态增长的问题,付出的最大代价就是:文件不再支持随机访问了,只能顺序访问
-
还有就是,多出的指针要占用额外的存储空间,使得存储器的空间利用率降低了
-
假如说一个文件占用10个磁盘块,也就是说有9个指针,只要这9个指针中的任意一个坏了,这个文件就不完整了,就没法用了
(2)链接分配——显示链接方案
为什么要引入显示链接方案
前面我们说的隐式链接方案中,是在各磁盘块的尾部加一个指针。显示链接方案其实就是将原本分散在各磁盘中的指针都集中起来,形成一个FAT表。有人这时候可能就会问,你这么做有啥好处呢?请看下面的场景:
这样假如说一个文件占用10个磁盘块,我就想将第五个磁盘块读入内存。如果采用隐式链接分配方案,那肯定是要先读第一个磁盘块,拿着第一个磁盘块最后的指针去读下一个磁盘块,这样依次读到第五个磁盘块。而如果我们用的是显示链接方案,我们就可以直接在FAT表中找到第五个磁盘块的指针,然后一次性就把第五个磁盘块读进来。
下图就是FAT表的简单示例,其中-1表示是文件的最后一个磁盘块,-2表示空闲的磁盘块

显示链接方案的优缺点
显示链接支持文件动态增长,也可以防止外部碎片的出现,还能支持随机访问(访问速度也更快了)。但代价就是:额外需要占用的存储空间更多了(FAT表在操作系统启动时就会被读入内存,从此以后常驻内存)
(3)索引分配——单级索引分配
到这里肯定有人还会问,显示链接方案这么好,为什么要引入索引分配呢?那肯定是显示链接方案也存在着它的问题。那是啥问题呢?
刚刚我们才说过:在显示链接方案中,FAT表需要常驻内存。无论我们是读一个文件,还是100个文件,都是这样。那对于读一个文件的情况,你把整个FAT表都读进来,显然有些杀鸡用牛刀了。这时候我们就在想,如果我们读哪个文件,只把这个文件相关的磁盘块信息读进来,那不就好了吗?索引分配就是这个思路!
索引分配策略会为每一个文件都分配一个专属的目录块,在其中创建一个小的文件目录,将属于这个文件的所有磁盘块号(磁盘块索引)都记录到这个文件目录中(具体例子见下图)

这样设计之后,在只读一个文件的场景下,采用索引分配,就比采用显示链接分配要好,因为索引分配只需要读取这个文件的目录块,而显示连接分配则需要读入整个FAT表
但是这样设计也是有缺点的,比如一个文件只占俩磁盘块,那你目录块中其实只需要存俩磁盘块号,但是目录块实际上可以存几百个磁盘块号,这就造成了空间的极大浪费
(3)索引分配——多级索引分配
为什么要引入多级索引分配?肯定是前面单级索引分配有不方便的地方。那哪里不方便呢?请看下面的场景
假如说我一个文件占用了10000个磁盘块,而我一个目录块里面最多存100个磁盘块号,那我就需要用100磁盘块来作为目录块。现在我想查找该文件目录中某个目录项,按折半查找来算,平均查找次数就是100次。而我要是采用二级目录的话,平均查找次数就是缩减到20次(这个我们前面在索引顺序文件中提到过,这里不再赘述)

当然这个多级索引也有缺点,比如说我想找某个文件第一个磁盘块的磁盘块号。如果用单级索引,只需要访问一次目录块,而用二级索引,就要访问两次。即对于某些比较靠前的磁盘块,多级索引会增加它们索引时访问磁盘的次数
(3)索引分配——混合索引分配
在多级索引分配的基础上,为了减少逻辑上靠前的磁盘块的索引时间,我们就引入了混合索引分配。典型的混合索引分配举例大家都很熟悉,就是我们linux系统的innode结构(这个你肯定很熟悉了,我就不多说了)

设备独立性软件
什么是设备独立性软件?设备独立性软件是干啥的?
设备独立性软件位于用户层软件与设备驱动程序之间,是操作系统中屏蔽设备硬件差异、让应用程序无需关注具体设备的中间层软件。

设备独立性软件的核心作用
- 向上提供一套统一的操作接口,无论底层是什么硬件设备,应用程序都通过一套标准命令调用设备功能
- 向上屏蔽硬件细节,更换硬件设备时,完成新硬件的适配工作,使得上层的应用程序无需修改应用代码,更换新硬件之后仍能正常运行
- 设备资源管理,具体来说包括:
- 缓冲区管理:用于缓和CPU与I/O设备的速度差异,提高CPU与I/O设备之间的并行性。
- 设备分配与回收:引入逻辑设备名,并实现逻辑设备名到物理设备名的转换;将设备、控制器和通道分配给进程,确保CPU与I/O设备之间能正常通信。
- 虚拟设备:将独占设备改造为共享设备的技术,以SPOOLing(假脱机技术)为例,可以将独占设备改造为共享设备,并将一台物理I/O设备虚拟为多台逻辑I/O设备,从而提高设备的利用率。
设备独立性软件的关键特点
- 与硬件无关,仅依赖设备的逻辑功能描述。
- 设备独立软件引入了逻辑设备和物理设备的概念,程序可以使用逻辑设备名来使用设备
- 是应用程序与设备驱动程序之间的桥梁。
- 包含设备控制逻辑、数据格式转换等核心功能
