这是 HNU 2023 年操作系统的期末试卷的答案及解析。
答案是我自己写的,和同学还有AI核对过了。
因为并非标准答案,所以可能仍有不足之处,欢迎大家在评论区讨论。
个人感觉:题型都比较经典,不算太难,可以在两小时之内完成。
一、论述题
(1)多核处理器调度采用单队列调度和多队列调度,分别存在什么样的问题,如何处理?
单队列调度
- 问题
- 存在竞态条件:多个处理器可能同时访问并修改某个共享资源
- 缓存抖动:任务在不同核之间频繁切换,破坏了 CPU 缓存中的数据局部性。
- 解决
- 使用互斥原语(比如锁)或者无锁数据结构来保护对共享资源的访问
- 亲和保留:处理器在取任务时优先尝试拿自己之前运行过的任务(如果还在队列中),保持“黏性”运行。
多队列调度
- 问题
负载不均:多个核的调度队列长度差异大,有的核忙碌、有的空闲,整体吞吐率下降。 - 解决
工作窃取:工作量较少的(源)队列不定期地“偷看”其他(目标)队列是不是比自己的工作多。如果目标队列比源队列(显著地)更满,就从目标队列“窃取”一个或多个工作,实现负载均衡。
(2)简述fork和exec各自功能和作用。
fork()
函数用于创建一个新的子进程,并且子进程的地址空间和父进程的一模一样
exec()
系列函数用于替换当前进程映像,加载一个新的可执行程序,并开始执行新程序的代码。
(3)什么是死锁?死锁产生需要哪四个必要条件?
死锁(Deadlock)是指两个及以上的线程在执行过程中,因竞争资源而造成一种互相等待的现象,使得它们都无法继续执行下去。
死锁的产生需要如下 4 个条件
互斥:线程对于需要的资源进行互斥的访问(例如一个线程抢到锁)。
持有并等待:线程持有了资源(例如已将持有的锁),同时又在等待其他资源(例如,需要获得的锁)。
非抢占:线程获得的资源(例如锁),不能被抢占。
循环等待:线程之间存在一个环路,环路上每个线程都额外持有一个资源,而这个资源又是下一个线程要申请的。
(4)磁盘驱动器一般包含有一定容量的缓存来提高磁盘的访问性能,缓存可以分为writeback和write
through两种类型,解释这两种类型缓存的优缺点。
Writeback缓存:
-
优点: 写操作先写入缓存,不立即写入磁盘,写入速度快、性能高;可合并多次写操作,减少磁盘I/O次数。
-
缺点: 断电或系统故障时未写入磁盘的数据可能丢失,数据安全性较低。
Write through缓存:
-
优点: 每次写操作同时写入缓存和磁盘,保证了数据一致性,断电时不易丢数据。
-
缺点: 写入速度较慢,每次写操作都涉及磁盘I/O,性能较低。
二、操作系统利用硬件的支持、采用受限直接执行机制实现了高效而可控地虚拟化CPU。下图2-1展示了操作系统利用该机制进行进程上下文切换的过程,其中涉及到操作系统(OS)、硬件(Hardware)和用户态程序(Program)三个实体,回答以下问题:
(1)硬件提供了哪些必要的支持?
- 两级模式:区分用户态/内核态,并对特权指令、内存访问等做检查
- 陷阱/中断机制:维护中断向量表,发生系统调用或定时器中断时自动切换到内核态,保存当前进程的寄存器并跳到对应中断处理函数入口
- 可编程定时器:由 OS 设置,定时产生中断,用于触发时间片切换
(2)从进程A(ProcessA)切换到进程B(ProcessB)执行的过程中,进程有哪些上下文需要保存(save)和恢复(restore)?分别由哪个实体负责?分别保存在哪里、从哪里恢复?
- 操作系统保存进程A的寄存器到A的进程控制块里,从进程B的进程控制块里恢复进程B的寄存器。
- 硬件保存进程A的寄存器到A的内核栈里,从进程B的内核栈里恢复进程B的寄存器。
三、分页式内存管理。
(1)假设一个128KB大小的地址空间,页面大小为128字节。假设页表项(PTE)和页目录项(PDE)的大小均为4字节。问:给定的地址空间需要多少位表示?偏移(offset)需要多少位表示?虚拟页号(VPN)需要多少位表示?页表需要多大的存储空间?页目录需要多大的存储空间?
地址位数:17位
offset:7位
VPN:10位
地址空间一共可以划分为
128
K
B
/
128
B
=
1024
=
2
10
128KB/128B=1024=2^{10}
128KB/128B=1024=210个页
一页可以容纳
128
/
4
=
32
=
2
5
128/4=32=2^5
128/4=32=25个页表项,所以页表项和页目录项都用5位来索引
页目录需要一页的存储空间,即128B
页表需要
128
B
/
4
B
∗
128
B
=
2
12
B
128B/4B*128B=2^{12}B
128B/4B∗128B=212B的存储空间
(2)假设一个程序的页面访问序列为4、3、2、1、3、5、4、3、2、1、5,并采用LRU算法,设分配给该程序的物理页帧数分别为3和4,计算该页面访问序列中发生的缺页次数和缺页率。
分配 3 个物理页框
访问的页面 | 更新后内存中的页面 | 是否缺页 |
---|---|---|
4 | 4 | y |
3 | 3,4 | y |
2 | 2,3,4 | y |
1 | 1,2,3 | y |
3 | 3,1,2 | n |
5 | 5,3,1 | y |
4 | 4,5,3 | y |
3 | 3,4,5 | n |
2 | 2,3,4 | y |
1 | 1,2,3 | y |
5 | 5,1,2 | y |
缺页次数:9 | ||
缺页率 = 9 / 11 =9/11 =9/11 |
分配 4 个物理页框
访问 | 更新后内存中的页面 | 命中/缺页 | 置换说明 |
---|---|---|---|
4 | [4] | 缺页 | |
3 | [4,3] | 缺页 | |
2 | [4,3,2] | 缺页 | |
1 | [4,3,2,1] | 缺页 | |
3 | [4,2,1,3] | 命中 | 更新最近使用 |
5 | [2,1,3,5] | 缺页 | 置换掉最久未用的 4 |
4 | [1,3,5,4] | 缺页 | 置换掉最久未用的 2 |
3 | [1,5,4,3] | 命中 | 更新最近使用 |
2 | [5,4,3,2] | 缺页 | 置换掉最久未用的 1 |
1 | [4,3,2,1] | 缺页 | 置换掉最久未用的 5 |
5 | [3,2,1,5] | 缺页 | 置换掉最久未用的 4 |
- 缺页次数:9
- 缺页率:9/11 ≈ 81.82%
四、分析图4-1所示使用信号量实现的有界缓冲区的生产者消费者代码,回答以下问题:
(1)当MAX=1时,在多个生产者和多个消费者的情况下,代码是否存在问题?
不存在问题。虽然共享资源buffer没有被锁保护,但是MAX=1决定了同一时间只有一个线程可以访问buffer这个资源。
(2)当MAX>1时,在两个生产者的情况下,代码存在什么问题,请给出分析;
存在竞态条件,函数get中对共享资源buffer的访问没有用锁保护,两个生产者可能对buffer的同一个位置放置数据,导致错误的结果。
(3)当MAX>1时,也可能存在多个消费者产生数据竞争(data race)的情况,请给出具体的例子并分析。
假设现在缓冲区已满,那么多个消费者可以同时调用get函数消费。第一个消费者先读取了buffer[use]的值,存入tmp。当它还没来得及更新变量use的值时,第二者消费者也调用了get,又读取了buffer[use]的值,存入tmp。
两个消费者消费了缓冲区同一个位置的值,产生了数据竞争的情况。
五、假设小明想要设计一个简单的文件系统,采用超级块+位图+inode表的结构,其中磁盘块大小为4KB,每个inode固定为256字节大小,试帮他分析如下问题:
(1)假设小明采用10个直接指针,1个间接指针和1个双重间接指针指向磁盘块,则最大可以支持多大的文件(指针大小为4字节,支持文件大小精确到KB)
( 10 + 1024 + 1024 ∗ 1024 ) ∗ 4 K B = 4198440 K B (10+1024+1024*1024)*4KB=4198440KB (10+1024+1024∗1024)∗4KB=4198440KB
(2)假设小明希望支持最大的文件为13MB,仍然采用10个直接指针,剩下的全部使用间接指针,小明在设计inode时需要包括多少个间接指针?
1个间接指针
=
1024
∗
4
K
B
=
4
M
B
=1024*4KB=4MB
=1024∗4KB=4MB
需要包括4个间接指针
(3)直接指针和间接指针在索引文件块时是否可以交换位置(即使用间接指针指向文件头中的块,直接指针指向文件尾中的块),为什么?
不建议交换位置
- 文件的开头部分通常被更频繁地访问,因此系统将这些部分交给访问速度更快的直接指针来处理,优化性能。
- 如果交换位置,用间接指针指向文件头的块,那么访问文件的整体开销将增大。
(4)如果磁盘大小为1GB,最多支持文件数量为40000个,超级块占用1个磁盘块,数据块位图和inode位图均块对齐,全部元数据(超级块+位图+inode表)需要多少磁盘块?
- 总盘块数
1 GB 4 KB = 2 30 2 12 = 2 18 = 262 144 块 \frac{1\,\text{GB}}{4\,\text{KB}} =\frac{2^{30}}{2^{12}}=2^{18}=262\,144\ \text{块} 4KB1GB=212230=218=262144 块 - 最大文件数 = inode 数
N i n o d e = 40 000 N_{\rm inode}=40\,000 Ninode=40000 - inode 表大小
40 000 × 256 B = 10 240 000 B, 10 240 000 4 096 ≈ 2 500 块 40\,000\times256\,\text{B} =10\,240\,000\,\text{B} ,\frac{10\,240\,000}{4\,096}\approx2\,500\ \text{块} 40000×256B=10240000B,409610240000≈2500 块 - 位图大小
- 数据块位图:需一位表示一个盘块,共 262 144 位
262 144 位 = 32 768 B → 32 768 4 096 = 8 块 262\,144\ \text{位} =32\,768\ \text{B} \rightarrow \frac{32\,768}{4\,096}=8\ \text{块} 262144 位=32768 B→409632768=8 块 - inode 位图:需一位表示一个 inode,共 40 000 位
40 000 位 = 5 000 B → ⌈ 5 000 4 096 ⌉ = 2 块 40\,000\ \text{位} =5\,000\ \text{B} \rightarrow \lceil\frac{5\,000}{4\,096}\rceil=2\ \text{块} 40000 位=5000 B→⌈40965000⌉=2 块
注:因为题目说了:“数据块位图和inode位图均块对齐”,所以这里的结果需要向上取整。
- 数据块位图:需一位表示一个盘块,共 262 144 位
- 超级块
占用 1 块 - 元数据总块数
1 ( 超级块 ) + 8 ( 数据位图 ) + 2 ( inode 位图 ) + 2 500 ( inode 表 ) = 2 511 块 1\ (\text{超级块}) +8\ (\text{数据位图}) +2\ (\text{inode 位图}) +2\,500\ (\text{inode 表}) =2\,511\ \text{块} 1 (超级块)+8 (数据位图)+2 (inode 位图)+2500 (inode 表)=2511 块
六、多副本的RAID1有着广泛的应用场景,如大型互联网厂商广泛采用的跨网络非校验型RAID本质上就是多副本的RAID1。下面请你就其简化情况一一单机三副本RAID1进行分析。假设单个磁盘的容量为1,随机工作负载下读、写的吞吐量均为RMB/s,连续工作负载下读、写的吞吐量均为SMB/s,给定N个磁盘组成3副本的RAID1阵列,分别详细分析并计算其
(1)容量;(2)可靠性;(3)顺序读、写的吞吐量;(4)随机读、写的吞吐量。
容量: N / 3 N/3 N/3
可靠性:由于每块数据都有三块副本,因此最少有两块失效仍然可以保持可靠。最多有 2 3 N \frac{2}{3}N 32N块数据失效,磁盘仍然可以正常工作。
顺序读:由于顺序读一次性只能读一个条带,而一个条带里面只有 1 3 \frac{1}{3} 31的非冗余数据,所以吞吐量为 1 3 N ∗ S \frac{1}{3}N*S 31N∗S
顺序写:顺序写一次最多只能写一个条带,所以吞吐量为 1 3 N ∗ S \frac{1}{3}N*S 31N∗S
随机读:顺序读可以同时读多个磁盘,所以吞吐量为 N ∗ R N*R N∗R
随机写:虽然随机写会分布在不同的条带,但是写一个数据块的同时还需要修改它的两个副本,所以吞吐量为 1 3 N ∗ R \frac{1}{3}N*R 31N∗R