操作系统复习要点
图片来源于上课的PPT
第一章 操作系统引论
操作系统概念: 操作系统是一组能有效的组织和管理软件和硬件资源,合理对各类作业进行调度,方便用户使用的程序的集合
分时、实时系统
- 分时系统
目标:共享
- 实时系统
目标:实时响应
操作系统的基本特征(4个)
并发(Concurrence)、共享(Sharing)、虚拟(Virtual)、异步(Asynchronism)
第二章 进程的描述与控制
进程概念: 进程是在系统中可以独立运行,并作为资源分配的基本单位,由机器指令、数据、堆栈组成,能够独立运行的实体
线程概念: 是操作系统能够进行运算调度的最小单位
进程控制块PCB
进程状态转换
- 就绪状态,进程已经分配到除CPU以外的所有资源
- 执行状态,获得CPU正在执行
- 阻塞状态,执行的进程受到某件事的打断
- 原语
Block:阻塞(是进程的主动行为)
Wake up:唤醒(阻塞->就绪)
Suspend:挂起
Active:激活
活动就绪被挂起后就是静止就绪
活动阻塞被挂起后就是静止阻塞
静止就绪被激活后就是活动就绪
静止阻塞被激活后就是活动阻塞
进程同步
主要任务:可再现性(让进程的执行具有确定性,按一定的规则共享资源并能很好的相互合作)
两种制约关系
- 互斥(间接相互制约关系,源于资源共享)
- 同步(直接相互制约关系,源于进程间的合作,即做完一件事后,才能做下一件事)
临界资源
概念: 一段时间只允许一个进程进行访问的资源,如打印机等。
临界区: 每个进程访问临界资源的代码段
各进程要互斥的进入临界区,实现临界资源互斥访问
进程同步规则
- 空闲让进(没有进程处于临界区了,就允许请求临界区的进程进入)
- 忙则等待(有进程在临界区,其他请求临界区的进程必须等待)
- 有限等待(在有限时间内进入临界区,避免死等)
- 让权等待(进程不能进入临界区时,应释放处理及,避免忙等)
信号量机制
信号量是一种有效的进程同步工具
用信号量标记临界资源是否被使用过
- 整形信号量
整形变量S标记资源的数量
wait(S){
while(S<=0)
S--;
}
signal(S){
S++;
}
当资源数量小于等于0时,会一直等待,不遵守”让权等待“原则
- 记录型信号量
用一个整形变量value代表资源数目,增加一个进程链表指针,链接所有等待进程
typedef struct{
int value;
struct process_control_block *list;
}semaphore
wait(semaphore *S){
S->value --;
if(S->value < 0) blcok(S->list);
}
signal(semaphore *S){
S->value ++;
if(S->value <=0 ) wakeup(S->list); //仍有等待的进程,唤醒
}
解决了让权等待问题,但有多种资源共享时,容易造成死锁
- AND型信号量
将进程执行需要的资源一次性分配,使用完一次性释放。要么全部分配,要不一个也不分配。
Swait(S1, S2, ..., Sn){
while(TRUE){
if(S1>=1 && ... Sn >= 1){
for(int i = 1; i <= n; i ++) Si --;
break;
}
else
将进程阻塞,放到第一个si<1的队列中
}
}
Ssignal(S1,S2,...,Sn){
while(TRUE){
for(int i = 1; i <= n; i ++){
Si ++;
将Si等待队列中的进程转入就绪队列
}
}
}
当一次需要申请N个资源时,可能造成死锁
- 信号量集
对AND型型号了进行扩充
资源数量Si,需求数量di,下限值ti
Si>=ti,否则不分配;允许分配Si-=di
Swait(S1,t1,d1,...,Sn,tn,dn)
Ssignal(S1,d1,...,Sn,dn)
特殊的几种信号量集
- Swait(S,d,d),只有一个信号量,每次申请d个,如果资源数<d,就不分配
- Swait(S,1,1),这个信号量集就是记录型信号量(S>1),或是互斥信号量(S=1)
- Swait(S,1,0),相当于开关,当S>=1时,允许多个进程进入,S变为0后,阻止进程进入。
⭐⭐经典进程同步问题(大题)
先定义变量,一定要有初始值。写对wait和signal的位置
生产者-消费者问题
信号量empty和full表示缓冲池中空缓冲区和满缓冲区的数量
信号量mute实现对缓冲池的互斥访问
in,out表示缓冲区下标
int in=0, out=0;
item buffer[n];
semaphore mutex=1, empty=n, full=0
void producer(){
do{
produce an item nextp;
wait(empty);
wait(mutex);
buffer[in]=nextp;
in=(in+1)%n;
signal(mutex);
signal(full);
}while(true);
}
void consumer(){
do{
wait(full);
wait(mutex);
nextc=buffer[out];
out=(out+1)%n;
signal(mutex);
signal(empty);
consumer an item nextc;
}while(true);
}
注意:wait的顺序不能改变,否则会发生死锁
用AND型信号量解决
int in=0, out=0;
item buffer[n];
semaphore mutex=1, empty=n, full=0
void producer(){
do{
produce an item nextp;
Swait(empty, mutex);
buffer[in]=nextp;
in=(in+1)%n;
Ssignal(mutex, full);
}while(true);
}
void consumer(){
do{
Swait(full, mutex);
nextc=buffer[out];
out=(out+1)%n;
Ssignal(mutex, empty);
consumer an item nextc;
}while(true);
}
哲学家问题(所有解决方法)
参考:操作系统——哲学家进餐问题的解决方法
解决方法:
- 规定至多4个哲学家先拿起左边的筷子(互斥信号量,counter=4)
- 用AND型信号量,两个临界资源都满足后才能进餐(AND型信号量)
- 规定奇数号的哲学家先拿左边再拿右边,偶数号哲学家反之
习题
- 现有四个进程R1、R2、W1、W2,它们共享可以存放一个数的缓冲器B。进程R1每次把来自键盘的一个数存入缓冲器B中,供进程W1输出;进程R2每次从磁盘上读一个数存放到缓冲器B中,供进程W2输出。为防止数据的丢失和重复打印,问怎样用信号量操作来协调这四个进程的并发执行
P1 W1, R2 W2是生产者消费者模型
共用的缓冲区也需要互斥访问
信号量S:互斥访问缓冲区,信号量S1:W1是否能输出(缓冲区是否有数据),信号量S2:W2是否能输出(缓冲区是否有数据)
S1,S2初值为0表示一开始缓冲区无数据
semaphore S=1, S1=S2=0;
producer R1(){
do{
wait(S);
从键盘读数据
signal(S1);
}while(true);
}
consumer W1(){
do{
wait(S1);
将缓冲区的数据输出
signal(S);
}while(true);
}
producer R2(){
do{
wait(S);
从键盘读入数据
signal(S2);
}while(true);
}
consumer W2(){
do{
wait(S2);
将缓冲区的数据输出
signal(S);
}while(true);
}
- 为了保证安全行驶,售票员必须关好车门,司机才能启动车辆,等车停稳,售票员才能打开车门,请使用信号量机制解决该问题
关好车门-->启动车辆
打开车门<--停止车辆
同步信号量关门、停车,初始值为0
driver(){
do{
wait(关门);
启动车辆
开车
到站停车
signal(停车);
}while(true);
}
conductor(){
do{
关门
signal(关门)
售票
wait(停车)
开门
}while(true);
}
- 请信号量机制解决缓冲区S和缓冲区t的一致性问题:get将字符放入缓冲区s,copy将字符从s中移到t中,put将字符从t中读出,必须按照顺序读入和读出,且不能漏字。
semaphore s_empty=1, s_full=0, t_empty=1, t_full=0;
get(){
do{
wait(s_empty);
将字符放入缓冲区s
signal(s_full);
}while(ture);
}
copy(){
do{
wait(s_full);
wait(t_empty);
将字符从s移到t
signal(t_full);
signal(s_empty);
}while(ture);
}
put(){
do{
wait(t_full);
将字符从t中读出
signal(t_empty);
}while(ture);
}
4. 单向车道问题(独木桥问题)
问题描述:
a,b 两点间是一段东西向的单行车道。请设计一个自动管理系统,管理规则如下:
(1)ab段间有车辆行驶时,同方向的车可以同时进入,但另一方向的车必须在段外等待;
(2)ab之间无车时,到达a(或b)的车辆可以进入,但不能从a、b点同时进入;
(3)某方向在ab段行驶的车辆驶出了ab段且无车辆进入时,应让另一方向等待的车辆进入。
这道题类似于读者-写者问题,同向的车子可以进入是读者,不同向的车不能同时进入是写者互斥。
条件1和2都是说同时只能有一个方向的车,需要一个互斥信号量实现单向车道的互斥访问
条件3说明一个方向的车辆驶出之后,就要释放单向车道的信号量
需要两个整形变量countab和countba,表示a到b或b到a的车辆数量,初值为0
需要两个互斥信号量mutexab和mutexba,实现对上面两个整形变量的互斥访问,初值为1
还需要一个互斥信号量s,实现对单向车道的互斥访问,初值为1,第一个车进入时wait(s),最后一个车驶出时signal(s)。
伪代码:
int countab=0, countba=0;
semaphore mutexab=1, mutexba=1, s=1;
Pab(){ //a开往b
while(true){
wait(mutexab);
if(countab==0) //第一辆车进入时,要等待单向车道的互斥访问
wait(s);
countab ++; //之后开进单向车道,a开往b的车加一
signal(mutexab);
a开往b
wait(mutexab);
countab --; //开出车道
if(countab == 0) //最后一辆车驶出时,要释放单向车道这个互斥资源
signal(s);
signal(mutexab);
}
}
Pba(){
while(true){
wait(mutexba);
if(countba == 0)
wait(s);
countba ++;
signal(mutexba);
从b开往a
wait(mutexba);
countba --;
if(countba == 0)
signal(s);
signal(mutexba);
}
}
第三章 处理及调度与死锁
调度的三个级别
- 高级调度(作业调度,调度对象是作业,主要用于多道批处理系统中)
根据算法,决定将外存后备队列上的哪几个作业调入内存,为它们创建进程、分配资源,并放入就绪队列 - 中级调度(内存调度,与挂起激活有关,提高内存利用率和系统吞吐量)
将暂时不能运行的进程调至外存等待,当它们具备运行条件且内存有空闲时,由中级调度决定将外存上哪些符合条件的进程重新调入内存,并修改状态为就绪 - 低级调度(进程调度,调度对象是进程)
根据算法,决定就绪队列上的哪个进程应获得处理机
作业调度算法⭐⭐(多道批处理系统)
会按照不同调度算法,写出调度顺序和周转时间
周转时间: 作业完成时间-到达时间
平均周转时间:
带权周转时间: 周转时间/服务时间
平均带权周转时间:
先来先服务(FCFS)调度算法
有利于长作业,不利于短作业,长作业带权周转时间短
短作业优先(SJF)调度算法
优先运行估计运行时间最短的进程
高响应比优先(HRRN)调度算法
死锁
死锁产生的必要条件(4个)
有一个不满足,就不会死锁
互斥条件、请求与保持条件、不可剥夺条件、环路等待条件
哲学家进餐问题的两个解决方法(至多4个能吃、分成奇偶数)破坏了环路等待条件
处理死锁的四个方法
-
预防死锁(通过破坏产生死锁条件中的几个来预防死锁)
破坏请求与保持条件:AND型信号量通过破坏请求与保持条件来预防死锁,一次给所有需要的资源;进程在运行过程中逐步释放用完的资源,再请求所需资源
破坏不可抢占条件:逐个申请资源,一旦资源无法满足,立刻释放所有资源
破坏循环等待条件:给资源赋序号
-
避免死锁(不事先采取限制性措施,在运行过程中防止进入不安全状态)
进行资源分配时,如何使系统不进入不安全状态
避免死锁的算法:银行家算法 -
检测死锁(不事先采取限制性措施,运行过程中产生死锁)
可通过检测即使检测到死锁的发生,然后采取措施解除死锁 -
解除死锁(检测到死锁后,常用采取措施)
常用方法:撤销进程,释放资源,将释放的资源分配给阻塞的进程,使之继续运行
⭐⭐银行家算法(避免死锁算法)
答题写出安全序列和矩阵
例一
边找安全序列边写矩阵
- 如何P1请求资源Request(1,0,2),不需要计算,因为P1是安全序列第一个,一定会分配给它
资源还有(2,3,0) - 如果P4请求资源(3,3,0)资源不够,让P4等待
- 如果P0请求资源(0,2,0),假定先为它分配资源,再进行安全性检查
由于P1已经分配过,目前资源分配情况如图
剩余资源无法满足任何进程,进入不安全状态,因此不能分配资源给P0
例二,课后题
死锁检测
资源分配图
简答题
圆圈表示进程,长方形表示资源池,点表示资源
进程指向资源表示进程申请了这个资源
资源指向进程表示这个资源分配给这个进程了
可以通过化简资源分配图,检测当前系统是否处于死锁状态
当资源分配图不可化简,S就处于死锁状态
例题
图1无法化简,有环存在;图2可以化简
第四章存储器管理
程序装入和链接的方式(所有)
装入的方式
- 绝对装入方式(将目标模块指定装入指定的内存位置,使用绝对地址)
- 可重定位装入方式(装入时,对指令和数据进行修改)
- 动态运行时装入方式(执行代码时进行地址转换)
可重定位装入方式:一旦装入内存,以后不再改变,也称静态可重定位
链接的方式 - 静态链接(事先链接成一个完整的装入模块)
- 装入时动态链接(边装入边链接,便于目标模块共享)
- 运行时动态链接(运行时发现没有目标模块就立即装入并且链接)
连续分配方式
动态分区分配方式
根据进程实际需要,动态分配内存空间
动态分区分配算法⭐⭐
- 首次适应算法(FF)
从头开始依次查找,找到第一个满足请求大小的分区 - 循环首次适应算法(NF)
从上次找到的空闲分区的下一个分区开始查找 - 最佳适应算法(BF)
找能满足请求的最小空闲分区 - 最坏适应算法(WF)
找能满足请求的最大空闲分区
内存的回收
例子
(1)首次适应算法:空闲块始址150、大小30k,空闲块始址280、大小20k,始址400、大小112k
(2)最佳适应算法:始址210、大小90k,始址400、大小30k,始址470、大小42k
(3)第一种在最后一块可以分配,第二种没有空闲区可以分配
离散分配方式
分页存储管理方式
- 页面碎片
最后一页通常装不满一块,形成了不可利用的碎片 - 页面大小
太大会使页面碎片过大
太小会使进程的页表过长,占用大量内存
页面大小是2的幂,通常为1KB ~ 8KB - 地址结构
例.页面大小为1KB,A=2170B,则P=2,d=122 - 页表
页表是页号和块号的对应关系 - 地址变换机构
当进程访问某个逻辑地址的数据时,先将页号和页表长度进行比较,如果没有越界,就计算页表始址 + 页号*页表项长度
找到该表项在页表中的位置,得到该页的物理块号,将页内地址送入物理地址寄存器中的块内地址,就实现了逻辑地址到物理地址的转换。
需要两次访问内存,第一次是访问页表,确定数据的物理地址,第二次是访问数据 - 快表
为了提高地址变换速度,在地址变换机构中增设一个具有并行查找能力的特殊高速缓冲寄存器,就是快表,存放当前访问的那些页表项。
先将页号送入高速缓冲寄存器,将此页号和寄存器中的所有页号进行比较,如果相匹配,就直接读出该页对应的物理块号;如果没有找到,还要再访问内存中的页表,找到后将物理块号送入地址寄存器,同时将此页表项存入快表的一次寄存器单元中。
分段存储管理方式(按逻辑划分)
-
分页和分段的区别
-
地址结构
-
段表
需要从物理地址中找出逻辑段对应的位置,每个段占有一个表项,包含段号、段长、基址(该段在内存中的起始地址)
-
地址变换机构
进行地址转换时,先将逻辑地址中的段号与段表长度进行比较,如果没有越界,根据段表的始址和段号,计算出该段在段表项中的位置,读取该段在内存中的起始地址;再检查段内地址是否超过该段长度,如果没有越界,就把该段的基址和段内地址相加,得到要访问内存的物理地址。
需要两次访问内存
段页式存储管理方式
- 基本原理
每个程序最多256段,每段16页,每页4KB
分段由用户按逻辑划分,分页由系统自动进行
- 地址变换结构
先将段号与段表长度进行比较,如果没有越界,就利用段号和段表始址找到该段在段表中的位置,得到该段的页表始址,利用逻辑地址中的段内页号获得对应页在页表中的位置,得出该页所在的物理块号,利用块号和页内地址得到物理地址。
需要三次访问内存,第一次是访问内存中的段表,获得页表始址;第二次是访问内存中的页表,取出该页所在的物理块号,计算物理地址;第三次是访问数据
第五章 虚拟存储器
虚拟存储器定义: 具有请求调入功能和置换功能,能从逻辑上对内存容量加以扩充的一种存储器系统
虚拟存储器的最大容量由计算机的地址结构确定。
虚存的实际容量由CPU的地址长和外存的容量决定,当CPU的地址长度能表示的大小远远大于外存容量时,虚存的实际容量为内存和外存容量之和;
当外存容量远大于CPU字长能表示的大小时,虚存的实际容量由CPU字长决定,若CPU有效地址长度为24位,则虚存容量为16M
一般情况下,CPU的地址长度能表示的大小都大于外存容量。因此虚拟存储器的逻辑容量=内存容量+外存容量
页面置换算法⭐⭐
进程在运行的过程中,若要访问的页面不在内存,需把它们调入内存,如果内存无空闲空间,系统需从内存调出一页程序送到磁盘的对换区中。哪一页被调出就用到了页面置换算法。
会算产生了多少缺页中断,缺页率是多少?
最佳置换算法(Optimal)
先入先出页面置换算法(FIFO)
最近最久未使用(LRU least recently used)
抖动
概念:刚被换出的页很快又要被访问,需要将它重新调入,同时选一页调出;此时刚被调出的页很快又被访问,又需要将它调入。发生了频繁的更换页面。
根本原因:要运行的进程太多,给每个进程分配的物理块太少,不能满足进程运行的基本要求。
Belady现象
由先入先出页面置换算法造成,分配的页面数增多,而缺页率提高
第六章 输入输出系统
I/O层次结构
中断处理程序和设备驱动程序的区别
设备驱动程序:与硬件直接相关,负责具体实现系统对设备发出的操作指令,驱动I/O设备工作的程序。
中断处理程序:保存被中断进程的CPU环境,转入相应的处理程序进行处理,处理完后再恢复被中断进程的现场后返回继续执行被中断的进程。
spooling技术
工作在用户区
特点:
- 提高了I/O速度
- 将独占设备改造为共享设备
- 实现了虚拟存储功能
引入缓冲作用
- 缓和CPU与I/O设备间速度不匹配的矛盾
- 减少对CPU的中断频率,放宽对CPU中断响应时间的限制
- 解决数据粒度不匹配问题
- 提高CPU和I/O设备间的并行性
磁盘调度算法⭐⭐
求磁头移动的距离,平均寻道长度等
先来先服务(FCFS)
最短寻道时间优先(SSTF)
可能造成饥饿现象
扫描算法(SCAN)
从里到外,再从外到里
像电梯一样
循环扫描算法(CSCAN)
磁头单向移动,反复扫描
第七章 文件管理
文件的逻辑结构
- 顺序文件
一系列记录由某种顺序排列,记录是定长记录或可变长记录
- 索引文件
给变长记录文件配备一个索引表
- 索引顺序文件
克服了变长记录不能存取,索引文件存储量较大的问题
思想:将顺序文件中的所有记录分组,为每组建一个索引项,指向每组的第一个记录。
查找方法:根据提供的关键字在索引表中查找,找到该组之后,获得该组的第一条记录位置,再在顺序文件中查找记录
平均查找记录数: 一个顺序文件中有N个记录,需查找N/2个记录;索引顺序文件平均查找√N个记录;两级索引顺序文件平均查找(3/2)√N(立方根)个记录
文件目录功能
树形目录结构最常用
1.实现“按名存取”
2.提高对目录的检索速度
3.文件共享
4.允许文件重名
文件共享
基于索引节点的共享方式
缺点:当两个进程共享一个文件,一个进程删除文件,不能删除索引节点,如果删除了索引节点,会导致另一个进程指针悬空
利用符号链实现文件共享(记录文件的路径名)
符号链优点:不会有指针悬空问题 缺点:多次读盘,访问文件开销大,增加启动磁盘的频率
第八章 磁盘存储器管理
外存组织方式
- 连续组织方式
- 链接组织方式
- 索引组织方式
九、常用Shell命令
Shell命令集可以为用户提供使用操作系统的接口,用户利用该接口与机器交互
- ls 列出目录问题所包含的目录项
- cd cp rm cat mv mkdir pwd
- wc统计行中字符
- fork创建进程 exit终止进程 wait等待子进程结束
- getp-id获得进程的标识符 getpgrp 获得进程的进程组的ID getppid 获得父进程的ID
- getuid 获得用户ID pause 进程暂停(挂起)