InkSoul/content/408/《操作系统》大题总结.md

20 KiB
Raw Permalink Blame History

title date
《操作系统》大题总结 2023-07-06T11:24:18+08:00

第二章大题考察同步互斥PV问题

生产者消费者问题

  • 特点
    • 进程与进程之间是生产资源-消费资源的关系
  • 解决步骤
    • 确定有几类进程,每个进程对应一个函数
    • 在函数内部用中文描述动作
      • 只做一次不加while
      • 不断重复加while
    • 在每一个动作之前确定需要什么注意隐含的互斥条件如对缓冲区的访问如有P操作则必定有V操作
    • 所有PV写完之后再定义信号量
    • 检查多个P操作连续出现的地方是否有死锁产生可能
      • 某个信号量的PV连续出现中间没有夹杂着其他的P不可能产生死锁连续多个P导致死锁时可尝试调整P顺序


Semaphore mutex1 = 1 //互斥访问F1
Semaphore mutex2 = 1//互斥访问F2
Semaphore empty1 = 10//F1上有几个空位
Semaphore full1 = 0//F1上有几个A
Semaphore empty2 = 10//F2上有几个空位
Semaphore full2 = 0 //F2上有几个B

//A车间
F_A(){
    while(1){
        生产一个产品A
        P(empty1)
        P(mutex1)
        A放到货架F1
        V(mutex1)
        V(full1)
    }
}

//B车间
F_B(){
    while(1){
        生产一个产品B
        P(empty2)
        P(mutex2)
        A放到货架F2
        V(mutex2)
        V(full2)
    }
}

//装配车间的工作描述
F_C(){
    while(1){
        P(full1)
        P(mutex1)
        F1取一个A
        V(mutex1)
        V(empty1)
        P(full2)
        P(mutex2)
        F2区一个B
        V(mutex2)
        V(empty2)
        AB组装成产品
    }
}


Semaphore well = 1;//用于互斥地访问水井
Semaphore vat = 1;//用于互斥地访问水缸
Semaphore empty = 10;//用于表示水缸中剩余空间能容纳的水的桶数
Semaphore full = 0;//表示水缸中的水的桶数
Semaphore pail = 3;//表示有多少个水桶可以用初值为3

//老和尚
while(1){
    P(full);
    P(pail);
    P(vat);
    从水缸中打一桶水;
    V(vat);
    V(empty);
    喝水
    V(pail)

}

//小和尚
while(1){
    P(empty);
    P(pail);
    P(well);
    从井中打一桶水
    V(well);
    P(vat);
    将水倒入水缸中
    V(vat);
    v(full);
    v(pail);
}

理发师问题

  • 特点
    • 进程之间是服务与被服务的关系
  • 主要解法
    int num = 0; //有几个顾客等待服务
    Semaphore Lock = 1;//互斥访问num
    Semaphore rest = 0;//同步信号量,用于实现若没顾客,服务人员休息等待,本质为服务人员排队队列
    Seamphore wait = 0;//同步信号量,用于实现,若服务人员都在忙,顾客休息等待,本质为一个让顾客排队的队列

    Sever(){
        while(1){
            P(Lock);
            if(num > 0){//有顾客
                V(Lock);
                V(wait);//唤醒一个顾客
                为顾客服务;
            }else{ //没顾客
                V(Lock);
                P(rest);//服务人员休息
            }
        }
    }

    Customer(){
        P(Lock);
        if(num > 等待人数上限(存在无规定人数上限可能)){
            V(Lock);
            离开这家店;
        }else{
            num ++;
            V(Lock);
            V(rest);//唤醒一个正在休息的服务人员
            P(wait);//等待被服务
            被服务;
        }
    }

Semaphore empty = 10;//空座位的数目
Semaphore mutex = 1;//互斥使用取号机
Semaphore full = 0;//无占用的座位
Semaphore service = 0;//等待叫号

cobegin
{
    porcess 顾客i
    {
        P(empty);//等空位
        P(mutex);//申请使用取号机
        从取号机获取一个号码;
        V(mutex);//取号完毕
        V(full);//通知营业员有新顾客
        P(service);//等待营业员叫号
        接受服务;
    }

    process 营业员
    {
        while(1){
            P(full);//没有顾客则休息
            V(empty);//离开座位
            V(service);//叫号
            为顾客服务;
        }
    }
}


哲学家问题

  • 特点
    • 只有一类进程,要占用多种资源才能运行
  • 关键点
    • 限制申请资源的顺序(不通用,不建议使用)
      • 如规定单号哲学家先取左筷子,双号先取右筷子
    • 限制并发进程数(通用,但并发度不高,不建议使用)
      • 如规定同一时间只能有一个哲学家就餐(禁止并行)
    • 让进程一口气取得所有资源,再开始运行(很通用且并发度高,建议使用)
      • 如哲学家只有能够取得两个筷子的时候才会就餐
  • 解法
    • 定义大锁
    • 定义资源数
    • 一口气拿所有资源
    • 做进程该做的事
    • 一口气归还所有资源
Semaphore Lock = 1;//互斥信号量,定义大锁
int a = 9;
int b = 3; 
int c = 6;

process(){
    while(1)
    {
        P(Lock);
        if(所有资源都拿够){
            所有资源int值减少;//题目会告知,每种资源所需量
            xxx资源//一口气拿走所有资源
            V(Lock);//拿完资源,解锁
            break;//跳出while循环
        }
        V(Lock);//资源不足,解锁,再次循环尝试获取
    }
    做进程该做的事(如哲学家进食)

    P(Lock);
    归还所有资源,所有资源int值增减
    V(Lock);
}


通常解

Semaphore bowl;//协调哲学家对碗的使用
Semaphore chopsticks[n];//协调哲学家对筷子的使用

for(int i = 0; i < n ;i++)
{
    chopsticks[i] = 1;//设置两名哲学家之间筷子的数量
}
bowl = min(n-1,m);//bowl 小于等于 n-1确保不产生死锁

cobegin
{
    while(1){ //哲学家i的程序
        思考;
        P(bowl);//取碗
        P(chopsticks[i]);//取左边筷子
        P(chopsticks[(i+1)%n]);//取右边筷子
        就餐;
        V(chopsticks[i]);
        V(chopsticks[(i+1)%n]);
        V(bowl);
    }
}

暴力解(考试建议解法)

Semaphore Lock = 1;
int bowl = m;
int chopstick[n];
for(int i = 0;i < n ; i++)
{
    chopstick[i] = 1;
}
philopher()
{
    while(1){//一次性拿下所有资源
        P(Lock);
        if(bowl <= 0)
        {
            V(Lock);
            continue;
        }
        if(!(chopstick[i] == 1 && chopstick[(i+1)%n]==1))
        {
            V(Lock);
            continue;
        }
        bowl --;
        chopstick[i] = 0;
        chopstick[(i+1)%n] = 0;
        V(Lock);
    }
    进餐
    P(Lock);//归还所有拿的资源
    bowl ++;
    chopstick[i] = 1;
    chopstick[(i+1)%n] = 1;
    V(Lock);
}

读者写者问题

  • 特点
    • 同类进程不互斥,异类进程互斥
  • 避免写者饥饿
    • 读写公平法
    • 写者优先法
  • 如何实现
    • 第一进程用之前负责上锁,最后一个进程用完之后负责解锁
Semaphore Lock = 1;//资源锁
int count = 0;//同类进程计数器
Semaphore mutex = 1;//对count 互斥访问
homie(){
    P(mutex);
    if(count ==0)
    {
        P(Lock);
    }
    count ++;
    V(mutex);
    使用资源;
    if(count == 1)
    {
        V(Lock);
    }
    count --;
    V(mutex);
}

实现同类互斥,异类也互斥

solo(){
    P(Lock);//使用前上锁
    使用资源;
    V(Lock);//用完了解锁
}

1

Semaphore bridge = 1;
NtoS(){
    P(bridge);
    通过桥;
    V(bridge);
}
StoN(){
    P(bridge);
    通过桥;
    V(bridge);
}

2

int countSN = 0;//表示从S到N的汽车数量
int countNS = 0;//表示从N到S的汽车数量
Semaphore mutexSN = 1;//保护countSN
Semaphore mutexNS = 1;//保护countNS
Semaphore bridge = 1;//互斥地访问桥
StoN(){//南到北
    P(mutexSN);
    //第一个进程上锁
    if(countSN==0)
        P(bridge);
    count ++;
    V(mutexSN);
    过桥;
    P(mutexSN);
    //最后一个进程解锁
    countSN--;
    if(countSN==0)
        V(bridge);
    V(mutexSN);
}

NtoS(){//北到南
    P(mutexNS);
    if(countNS==0)
        P(bridge);
    countNS++;
    V(mutexNS);
    过桥;
    P(mutexNS);
    countNS--;
    if(countNS ==0)
        V(bridge);
    V(mutexNS);
}

Semaphore room = 1;
Semaphore mutex1 = 1;
Semaphore mutex2 = 1;
Semaphore mutex3 = 1;
int count1 = 0;
int count2 = 0;
int count3 = 0;

P1(){
    P(mutex1);
    count1 ++;
    //第一个上锁
    if(count1 == 1)
    {
        P(room);
    }
    V(mutex1);
    看影片1;
    P(mutex1);
    count1 --;
    //最后一个解锁
    if(count1 == 0)
    {
        V(room);
    }
    V(mutex1);
}

P2(){
    P(mutex2);
    count2 ++;
    //第一个上锁
    if(count2 == 1)
    {
        P(room);
    }
    V(mutex2);
    看影片2;
    P(mutex2);
    count2 --;
    //最后一个解锁
    if(count2 == 0)
    {
        V(room);
    }
    V(mutex2);
}

P3(){
    P(mutex3);
    count3 ++;
    //第一个上锁
    if(count3 == 1)
    {
        P(room);
    }
    V(mutex3);
    看影片3;
    P(mutex3);
    count3 --;
    //最后一个解锁
    if(count3 == 0)
    {
        V(room);
    }
    V(mutex3);
}


第三章大题,考察请求分页,基本分页,页面置换问题

  • 各概念间的推导计算
    • 一级页表+TLB+请求分页
    • 二级页表+请求分页+TLB
      • 页目录号的位数表示的大小(表示有多少个目录项)* 每个目录项的大小 = 页目录表的大小
      • 页目录表的起始地址 + 页目录号 * 页目录项的长度 = 页目录项的物理地址
  • 示例图中挖掘隐藏信息
    • 熟悉各类常见图示
    • 注意TLB组相联映射、全相联映射的图示画法
    • 深入理解组相联映射全相联映射方式下查询TLB的原理区别
  • 基于地址转化过程的分析
    • 熟悉各种状况下地址转化的过程
      • 一级页表+虚拟内存+TLB
      • 二级页表+虚拟内存+TLB

TLB+二级页表+Cache(全相联映射)

TLB+二级页表+Cache(2路组相联映射)

TLB + 二级页表 + Cache(直接映射)


1
页的大小 = 块的大小 = 2^{12} = 4 KB
页表的大小 = 2^{20} \times 4B = 4 MB
2
页目录号 = (((unsigned int)(LA))>>22) & 0x3FF
页表索引 = (((unsigned int)(LA))>>12) & 0x3FF
3
00008000H其页号为0008 \rightarrow 页号为8 \rightarrow 对应页表第8个页表项
第8个页表项物理地址 = 00200000H + 8 \times 页表项的字节数
= 00200000H + 8 \times 4 = 00200020H
第9个页表项及其物理地址 = 00200000H + 8 \times = 00200024H
页框号1 = 00900000H页框号2 = 00900000H + 8KB = 00901000H
代码2起始物理地址 = 00901000H

页的大小 = 4KB = $2^{12}$B页面位移比虚拟地址低12位

访问2362H即 0010 0011 0110 0010 其对应页号为2

访问快表10ns \rightarrow初始快表空\rightarrow访问页表100ns得到页框号\rightarrow 合成物理地址后访问主存100ns

共 10 + 100 + 100 = 210 ns

访问1565H即 0001 0101 0110 0101 其对应页号为2

访问快表10ns ,空\rightarrow访问页表100ns,空\rightarrow 缺页中断处理10^8$ns \rightarrow$访问快表10ns$\rightarrow$合成物理地址后访问主存100ns

共 10 + 100 + 10^8 + 10 + 100 = 100000220 ns

访问25A5H即 0010 0101 1010 0101 其对应页号为2 访问快表10ns \rightarrow合成物理地址后访问主存100ns

共 10 + 100 = 110 ns

2

1565H = 0001 0101 0110 0101

页号为1产生缺页中断驻留集 = 2从页表淘汰1个页面

使用LRU淘汰页号0 \rightarrow 1565H对应页框号为101H 物理地址 = 101565H

1

页的大小 = 1KB = $2^{10}$B

逻辑地址低10位为页偏移

17CAH \rightarrow 0001 0111 1100 1010

页号为 000101 = 5

2

根据FIFO置换页号0对应页框号7

物理地址为 0001 1111 1100 1010 = 1FCAH

3

根据clock 置换页号2对应页框号2

物理地址为 0000 1011 1100 1010 = 0BCAH

1

0页对应空闲页第3个即页框号 = 1

2

11>10,说明此时发生第三轮扫描

第二轮中32,15,41,均未被访问,处于空闲页表中

此时重新访问第一页则页框号32被重新放回驻留集

3

2页从未被访问此时空闲链为41,15取其头41即页框号41

4

适合,程序的时间局部性越好,从空闲页框链表中重新取回的机会越大,该策略优势越明显

1

页的大小 = $2^{12}$B

页框大小 = $2^{12}$B

虚拟地址空间大小 = 2^{10} \times 2^{10} = 2^{20}

2

页目录所占页数 = \frac{2^{10} \times 4B}{2^{12}} = 1

页表所占页数 = \frac{2^{10} \times 2^{10} \times 4B}{2^{12}} = 2^{10}

共占 2^{10} + 1 = 1025

3

0100 0000H对应页目录号 0000 0001 00 = 4

0111 2048H对应页目录号 0000 0001 00 = 4

访问的是同一个二级页表,即供访问一个二级页表

1

页目录号 = 610位 页内索引 = 610位偏移 = 812位

所以十六进制为 0000 0001 1000 0000 0110 0000 0000 1000

= 01806008H

(2)

物理地址

进程切换时,地址空间发生了改变,对应页目录块及始址也改变 \rightarrow PDBR改变

同一进程线程切换时,地址空间不变,线程的页目录不变\rightarrow PDBR不改变

3

使用位\rightarrow访问字段

修改位\rightarrow修改字段

1

页面大小 = 2^{12} = 4KB

一个页可以存\frac{4KB}{4} = 1024个数组 = a数组的一行

a按行优先方式存放10800000H虚页号为10800H

a[0]行存放在10800H的页面中 a[1]行存放在10801H的页面中

a[1][2]的虚拟地址为 10801000H + 4 \times 2 = 10801008H

10801008H = 0001 0000 1000 0000 0001 0000 0000 1000

页目录号 = 0001000010 = 042H

页号 = 0000000001 = 001H

页目录项物理地址 = 00201000H + 4 $\times 42$H = 00201108H

物理地址 003010000 + 001H \times 4 = 00301004H

2

必须连续,不一定连续

3

按行遍历局部性更好。每个页面正好放一整行的元素

按行存放说明一行元素存放在同一页面中,局部性也就更好

第四章大题:混合文件索引

显式链表分配法FAT文件系统即DOS

混合索引法Unix文件系统

考题

1

连续存放更合适,磁盘寻道时间更短,文件随机访问效率更高

加入字段<起始块号,块数>

2

FCB集中存放文件数据集中存放

这样在随机查找文件名时只需访问FCB对应的块可减少磁头移动和磁盘IO访问次数

1

磁盘块总数 = \frac{4TB}{1KB} = \frac{4 \times 2^40}{2^10} = 2^32

块号至少占 \frac{32}{8} = 4B

512B的索引区能够容纳\frac{512B}{4B} = 128个索引项

文件最大长度 = 1KB \times 128 = 128KB

2

索引项 = \frac{504B}{6B} = 84

单个文件最大长度 = 2^{16} \times 1KB + 84 \times 1KB = 84KB + 2^{26}B

起始块号占4B块数占4B

起始块号可寻址2^{32}个块共4TB即整个系统空间

块数可表示2^{32}个块共4TB

1

dir目录文件

文件名 簇号
dir1 48

dir1 目录文件

文件名 簇号
file1 100
file2 200

2

簇号2B = 16位 \rightarrow FAT表允许2^{15}个表项

FAT最大长度 = 2^{16} \times 2B = 128KB

文件最大长度 = 2^{16} \times 4KB = 256MB

3

106存放在100号表项中

108存放在106号表项中

4

先访问dir1即第48个簇

得到file1的第一个簇号在FAT中查找file1的第5000个字节所在簇号最后访问该簇号4KB = 4096B < 5000B

即访问48号簇106号簇

1

把文件前29条前移移动一条记录读出和存回磁盘各一次访盘

共访盘 29 \times 2 +1 = 59

F的文件控制区的起始块号和文件长度内容会发生改变

2

找到系统第29块访盘29次

把29的下块地址给新块把新块存回磁盘访盘一次

修改内存第29块的下块地址字段再存回磁盘访盘一次

共29 + 1 + 1 = 31 次

4B即32位可寻址2^{32} = 4G块存储块每块大小1KB = 1024B

其中4B为指针1020B为数据

文件长度为1020B \times 4G = 4080GB

1

1个簇最多有\frac{4KB}{4B} = 1024个地址项

直接地址8个8 \times 4KB 二级地址1个2^{20}\times4KB

一级地址1个2^{10} \times 4KB 三级地址1个2^{30} \times 4KB

最大文件长度 = 32KB + 4MB + 4GB + 4TB

2

最多索引结点数 = \frac{2^20 \times 4KB}{64B} = 2^{26} = 64M

\frac{5600B}{4KB} > 1 \rightarrow 一个图像占两个簇

\frac{512M}{2} = 256M \rightarrow 可存放256M个文件

但索引结点数64M < 256M

所以最多存放64M个图像文件

3

6KB < 8\times 4KB

F_1采用直接索引\rightarrow只要访问索引结点的直接地址项

32KB < 40KB < 32KB + 4MB

F_2采用一级索引\rightarrow 还需读一级索引表

所以两者不相同

第五章

大题

1

用位图表示磁盘的空闲空间,每位表示一个磁盘块的空闲状态

共需\frac{16384}{32} = 512个字=512 \times 4B = 2KB,正好可以放在系统提供的内存中

2

磁盘访问序列为120 \rightarrow 30 \rightarrow 50 \rightarrow 90

移动磁道数分别为 20,90,20,40

移动磁道时间 = 1ms \times (20 + 90 + 20 + 40) = 170ms

一次旋转时间 = \frac{60}{6000} = 0.01s = 10ms

总的旋转延迟 = 4 \times \frac{1}{2} \times(一次旋转时间) = 4\times 5ms = 20ms

总读取时间 = 4 \times \frac{10ms}{100} = 4 \times 0.1ms = 0.4ms

总时间 = 170ms+20ms+0.4ms = 190.4ms

3

FCFS(先来先服务调度算法)更高效

Flash半导体存储器不需要考虑寻道时间和旋转延迟

可直接按IO请求的先后顺序服务

1

容量 = 300 \times 10 \times 200 \times 512B = 3 \times 10^5KB

2

85号柱面对应簇号 85000~85999一个簇有2个扇区

访问次序为 100260 \rightarrow 101660 \rightarrow 110560 \rightarrow 60005

3

\frac{200 \times 10}{2} = 1000

100 \times 1000 = 100000

100530 - 100000 = 530

\frac{530}{100} = 5

30 \times 2 = 60

柱面号1000磁头号5扇区号60

将簇号转换成磁盘物理地址的过程由磁盘驱动程序完成

1

ROM中的引导程序\rightarrow磁盘引导程序\rightarrow分区引导程序$\rightarrow$OS的初始化程序

2

磁盘的物理格式化\rightarrow对磁盘分区\rightarrow逻辑格式化$\rightarrow$OS的安装

3

磁盘扇区的划分\rightarrow磁盘的物理格式化\rightarrow文件根目录的建立\rightarrow逻辑格式化操作