文章目录
处理器管理(15分)
进程和线程的关系
定义:
- 进程:进程是动态的,是程序的一次执行过程。进程是由程序段、数据段、PCB组成
- 线程:线程是一个基本的CPU执行单元,也是程序执行流的最小单位。
引入线程后,有什么变化: - 资源分配、调度:
- 传统的进程机制中,进程是资源分配、资源调度的基本单位
- 引入线程后,进程是资源分配的基本单位,线程是资源调度的基本单位
- 并发性:
- 传统机制中,只能进程间并发
- 引入线程后,各线程间也能并发,提升了并发度
- 系统开销:
- 传统的进程间并发,需要切换进程的运行环境,系统开销大
- 线程间并发,如果是同一进程内的线程并发,则不需要切换进程运行环境,系统开销小
进程的状态转换
三态/五态模型如下图,很详细了:
进程控制块(PCB)的作用
PCB的作用:
- PCB保存了一个进程的许多主要信息,这些信息主要有一下几点:
- 进程描述信息:OS需要记录PID(进程号)、UID(创建这个进程的用户号)等信息
- 进程控制和管理信息:OS需要记录进程的运行情况(CPU使用时间、磁盘使用情况、网络流量使用情况等)
- 资源分配清单:OS需要记录给进程分配了多少资源(分配了多少内存、正在使用哪些I/O设备、正在使用哪些文件)
- 处理机相关信息:OS需要记录PSW、PC等等各种寄存器的值,以便于进程切换
处理机调度算法
性能指标:
- 周转时间=作业完成时间-作业提交时间
- 平均周转时间=各作业周转时间之和/作业数量
- 带权周转时间:(作业完成时间-作业提交时间)/作业实际运行时间
- 平均带权周转时间:各作业带权周转时间之和/作业数量
先来先服务算法:
例题2:三个作业的同时到达系统并立即进入调度,作业名/所需CPU时间:作业1/28、作业2/9、作业3/3。采用FCFS算法,求平均周转时间?
若三个作业的提交顺序是1、2、3,则平均周转时间为:35
若三个作业的提交顺序是2、1、3,则平均周转时间为:28.6
若三个作业的提交顺序是3、2、1,则平均周转时间为:18.3
SJF算法(非抢占式):
例题2:四个作业同时到达系统并进入调度,作业名/所需CPU时间:作业1/9、作业2/4、作业3/10、作业4/8。采用SJF算法,求调度顺序、求平均周转时间、平均带权周转时间?
作业调度的顺序为:2、4、1、3,平均周转时间为:17,平均带权周转时间为:1.98
高响应比优先算法:
例题2:四个作业到达系统的时间/所需的CPU时间为:作业1—0/20、作业2—5/15、作业3—10/5、作业4—15/10,若使用高响应比优先算法,求调度顺序、求平均周转时间、平均带权周转时间?
响应比=(等待时间+要求服务时间)/要求服务时间
注意:等待时间会实时更新,每一时刻需要重新计算!
调度顺序:1、3、4、2,平均周转时间为:26.25,平均带权周转时间:2.46
进程管理(30分)
伯恩斯坦条件
并发进程的无关性是程序的执行和时间无关的一个充分条件
与时间有关的错误
定义:对于一组交往的并发进程,执行的相对速度无法相互控制,各种与时间有关的错误就可能出现。
与时间有关错误的表现形式:
- 结果唯一
- 结果不唯一
飞机售票问题(结果不唯一):
//旅客一进程
void T1(){
{按旅客订票要求找到Aj};
int X1=Aj;
if(X1>=1){
X1--;
Aj=X1;
{输出一张票};
}else{
{输出信息"票已售完"};
}
}
//旅客二进程
void T2(){
{按旅客订票要求找到Aj};
int X1=Aj;
if(X1>=1){
X1--;
Aj=X1;
{输出一张票};
}else{
{输出信息"票已售完"};
}
}
申请和归还主存资源问题(永远等待):
//借进程
//memory为初始主存容量
int X=memory;
void borrow(int B){
while(B>X)
{进程进入等待主存资源的队列};
X=X-B;
{修改主存分配表,进程获得主存资源}
}
//还进程
void return(int B){
X=X+B;
{修改主存分配表};
{释放等主存资源进程};
}
临界区管理原则
临界资源:在计算机中,有些共享资源在同一时刻只能被一个进程访问,这些资源就被称为临界资源。
临界区:访问临界资源的那段代码就叫做临界区
临界区管理的原则:
- 一次至多一个进程能够进入临界区执行
- 如果已有进程在临界区,其它试图进入的进程需要等待
- 进入临界区的进程应在有限时间内退出,以便让等待进程的中的一个进入
- 临界区调度原则:
- 互斥使用、用空让进
- 忙则等待、有限等待
- 择一而入、算法可行
二元/多元信号量的定义以及对应的PV操作(请给出伪代码形式)
二元信号量及其PV操作:
typedef struct{
int value;//value只能取0和1
struct process *L;
}semaphore;
P操作:
void BP(semaphore S){
if(S.value==1){
S.value=0;
}else{
block(S.L);
}
}
V操作:
void signal(semaphore S){
if(S.L is empty()){
S.value=1;
}else{
wakeup(S.L);
}
}
多元信号量及其PV操作:
定义:
typedef struct{
int value;//value值可以取多个值
struct process *L;
}semaphore;
P操作:
void wait(semaphore S){
S.value--;
if(S.value<0){
add this process to S.L;
block(S.L);
}
}
V操作:
void signal(semaphore S){
S.value++;
if(S.value<=0){
remove a process P from S.L;
wakeup(P);
}
}
PV操作的经典问题(七选二,重点关注作业题)
生产者消费者(多生产者-多消费者):
课本例题修改(多生产者-多消费者)(作业题):
修改教材多个生产者和多个消费者共享多个缓冲区的算法,使得生产者之间放产品和消费者之间取产品之间实现并发
M个生产者,N个消费者,K个缓冲区
semaphore mutex=1;//互斥信号量,实现互斥访问临界区
semaphore empty=k;//同步信号量,表示空闲缓冲区的数量
semaphore full=0;//同步信号量,表示非空缓冲区的数量(产品数量)
Buffer B[K];
in=0,out=0;
Producer(){
while(1){
生产一个产品;
P(empty);//申请一个空闲缓冲区
P(mutex);
将产品放进B[in];
in=(in+1)%K;
V(mutex);
V(full);//释放一个产品
}
}
Consumer(){
while(1){
P(full);//申请一个产品
P(mutex);
从B[out]取走一个产品;
out=(out+1)%K;
V(mutex);
V(empty);//释放一个空闲缓冲区
消费产品
}
}
吃水果(多生产者-多消费者)(作业题):
和尚打水(多生产者-多消费者)(作业题):
有老、小和尚若干,水桶若干。打水取水都需要水桶,水缸只有一个,缸口仅能容纳一个桶出入,有水井一眼,井口仅容纳一个桶出入。小和尚需要给老和尚打水。
semaphore well=1;//互斥信号量,用于互斥访问水井
semaphore vat=1;//互斥信号量,用于互斥访问水缸
semaphore pail=n;//互斥信号量,用于实现对某一个水桶的互斥使用,初值为n(互斥信号量一般都为1)
semaphore empty=m;//同步信号量,表示水缸中剩余空间能容纳的水的桶数,初值为m
semaphore full=0;//同步信号量,表示水缸中的已有的水的桶数,初值为0
//小和尚
while(1){
P(empty);//向水缸申请一个空位
P(pail);
P(well);
从水井取一桶水;
P(well);
运水;
P(vat);
倒水;
V(vat);
V(full);//在水缸中释放一桶水
V(pail);
}
//老和尚
while(1){
P(full);//向水缸申请一桶水
P(pail);
P(vat);
从水缸取走一桶水;
V(vat);
P(empty);//在水缸中释放一个空位
喝水
V(pail);
}
吸烟者(单生产者-多消费者)(作业题):
因为缓冲区大小为1,且同一时刻,四个同步信号量中至多有一个为1,所以这题不需要设置互斥信号量mutex,只需要设置上述四个同步信号量。
读者写者(复杂的互斥问题)(我感觉不会考):
哲学家就餐(复杂的互斥问题)(我感觉不会考):
方案一:
因为会发生死锁现象,所以上面这种解决方案不可行。
方案二:
死锁(20分)
死锁的条件
产生死锁必须同时满足以下四个条件,只要其中一个条件不成立,死锁就不会发生:
互斥条件:只有对必须互斥使用的资源的争抢才会导致死锁(如哲学家的筷子、打印机设备)。像内存、扬声器这样可以让多个进程使用的资源是不会导致死锁的(因为进程不用阻塞等待这种资源)。
不剥夺条件:进程所获得的资源在未使用完之前,不能由其他进程强行夺走,只能主动释放。
请求和保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源又被其它进程占有,此时请求进程被阻塞,但又对自己已有的资源保持不放。
循环等待条件:存在一种进程资源的循环等待链,链中的每一个进程已获得的资源同时被下一个进程所请求。
层次化分配策略的证明(预防死锁)
循环等待条件:存在某一种进程资源循环等待链,链中的每一个进程已获得的资源同时被下一个进程所请求。
可采用顺序资源分配法。首先给系统中的资源编号,规定每个进程必须按照编号递增的顺序请求资源,同类资源(即编号相同的资源)一次性申请完。
原理分析:一个进程只有已占用小编号资源时,才有资格申请更大编号的资源。按照此规则,已持有更大编号的进程不可能逆向地回来申请小编号地资源,从而就不会产生循环等待的现象。
该策略的缺点:
- 不方便增加新的设备,因为可能需要重新分配所有的编号
- 进程实际使用资源的顺序可能和编号递增的顺序不一致,会导致资源浪费
- 必须按规定次序申请资源,用户编程麻烦
银行家算法(避免死锁)
安全性算法(手算版):
1.0版本—处于安全状态
2.0版本—处于不安全状态
死锁定理(检测死锁)
为了能对系统是否发生了死锁进行检测,必须:
- 用某种数据结构来保存资源的请求和分配
- 提供一种算法,利用上述的信息来检查系统是否进入死锁状态
存储管理(35分)
为什么提出分页/分段/段页式存储管理
- 分页存储为什么提出:连续分配分配管理方式会形成许多的碎片,虽然可以使用拼接、紧凑技术可以将许多碎片拼接成大块的空闲空间,但是**代价非常大。**因此,提出了分页式存储管理
- 分段式存储为什么提出:分页式存储管理内存空间的利用率高,不会产生外部碎片,只会产生少量的内部碎片;但是,分页式存储管理不方便按照逻辑模块实现信息的共享和保护。因此,提出了分段式存储管理
- 段页式存储为什么提出:分段式存储管理虽然可以很方便地按照逻辑模块实现信息的共享和保护;但是,如果段长过长,为其分配很大的连续空间会很不方便,此外,还会**产生外部碎片。**因此,提出了综合页式管理和段式管理优点的段页式管理。
分页式存储管理如何实现逻辑地址到物理地址的转换
页面的尺寸为什么是2的整数次幂?
逻辑地址的划分:
给出页面大小、页表、逻辑地址,如何计算物理地址:
(一般来说,题目中给出的页面大小都是2的整数次幂,计算方式如下)
上面这张图逻辑地址4097B的物理地址有问题:应该是00000000000000001001000000000001
基本地址变换机构:
基本地址变换机构可以借助进程的页表将逻辑地址转换成物理地址。
通常会在系统中设置一个页表寄存器(PTR),存放页表在内存中的起始地址F和页表长度M。进程未执行时,页表的始址和页表长度放在进程控制块(PCB)中,当进程被调度时,OS内核会把它们放到页表寄存器中。
注意:页面的大小是2的正数幂
设页面的大小为L,逻辑地址A到物理地址E的变换过程如下:
分段式存储管理如果实现逻辑地址到物理地址的转换(逻辑地址如何划分)
逻辑地址的划分:
基本地址变换机构(同给出段表、逻辑地址,如果计算物理地址这个问题):
分段式/分页式存储管理的优缺点
页面替换算法(页面被替换的顺序)
最佳置换算法:
最佳置换算法可以保证最低的缺页率,但实际上,最有在进程执行的过程中才能知道接下来会访问到的是哪个页面。OS无法提前预判页面访问序列。因此,最佳置换算法是无法实现的。
先进先出置换算法:
最近最久未使用算法(LRU)(必考):
时钟置换算法(NRU)(低频,可以不看)
1.0版本:
2.0升级版: