概述
本文根据博主自身学习经验和网上资料,结合课本(《操作系统教程:第5版》费翔林著)及配套PPT,总结出来的期末复习笔记,主要对知识结构和重点内容进行了大致梳理,细节部分可参照课本或查阅其它相关内容进行完善。本文章仅供各位同学参考复习。
操作系统复习笔记
一、概述
1.CPU利用率
假设程序平均等地I/O操作的时间占其运行时间的比例为p,当内存中有n道程序时,所有程序都等待I/O操作的概率为
p
n
p^n
pn,即此时CPU是空闲的,那么CPU利用率为:
1
−
p
n
1-p^n
1−pn
2.API、库函数和系统调用
- 系统调用:内核提供了一系列具有预订功能的服务例程,通过一组称为系统调用的接口呈现给用户。系统调用把应用程序的请求传送至内核,调用相应服务例程完成所需处理,将处理结果返回给用户。系统调用是应用程序获得操作系统服务的唯一途径。
- API:API是一个函数定义,它强调的是如何通过接口来获得所需要的服务,注意系统调用只是一种API,而API还包括各种各样的编程接口。
- 库函数:库函数(Library function)是将函数封装入库,供用户使用的一种方式。
3.系统调用和函数调用之间的区别
- 调用形式和实现方式不同:
函数调用所指向的地址是固定不变的,但系统调用中不包含内核服务例程入口地址,仅提供功能号,按功能号调用。
函数调用是在用户态执行的,只能访问用户栈;系统调用要通过陷阱机制,从用户态转换到内核态。服务例程在内核态执行并访问核心栈。 - 被调用代码的位置不同:
函数调用是静态调用,调用程序和调用代码处于同一程序内,经链接后可作为目标代码的一部分,这是用户级程序;
系统调用是动态调用,系统调用的服务例程位于操作系统中,这是系统级程序。 - 提供方式不同:
函数调用通常由编程语言提供;系统调用由操作系统提供。
4.操作系统内核
- 内核的概念:内核(Kernel)是一组程序模块,作为可信软件来提供支持进程并发执行的基本功能和基本操作,通常驻留在内核空间,运行于内核态,具有直接访问硬件设备和所有内存空间的权限,是仅有的能够执行特权指令的程序。
- 内核的功能:中断处理、时钟管理、短程调度、原语管理。
5.机制与策略分离原则
机制与策略分离原则是让程序中的独立部分分别来实现机制与策略,可以归结为以下三点:
- 机制由操作系统实现,策略留给用户实现。
- 机制放在底层,策略放在高层。
- 机制集中在少数模块,策略可散步在系统多处。
例子:
- 在进程调度机制中,调度算法以某种形式参数化,参数可由应用进程填写。尽管主进程本身并不参与调度,它却可以控制子进程被调度的细节。
二、处理器管理
处理器管理是操作系统的重要组成部分,负责管理、调度和分派计算机系统的重要资源——处理器,并控制程序执行。
涉及两方面内容:
- 处理器(资源)分配
- 运行的程序(进程)调度
1.指令系统和寄存器
- 特权指令:指仅在内核态下才能使用的指令,这些指令涉及改变机器状态、修改寄存器内容、启动设备I/O等。
- 非特权指令:在目态和管态下都能工作。
操作系统程序能够执行全部机器指令,应用程序只能使用非特权指令。
程序状态字(PSW):用于区别不同程序的处理器工作状态。每个程序都有一个与其执行相关的PSW,而每个处理器均设置一组相关寄存器用于存储PSW信息。
PSW的主要内容:
- 程序基本状态(程序计数器、条件码、状态位)
- 中断码
- 中断屏蔽位
2.中断技术
中断是指程序执行过程中,当发生某个事件时,中止(暂停)CPU上现行程序的运行,引出处理该事件的服务程序执行的过程。中断事件处理需要硬件和软件配合完成。
3.中断处理程序
具体功能:
- 保护一些未被硬件保护的现场信息
- 识别中断源,分析中断产生的原因
- 处理发生的中断事件
- 恢复正常操作
实现方法:
- 向量地址是中断服务程序的入口
- 中断向量表
中断事件处理的一般过程:
-
发现中断源(硬件)
-
保护现场(硬件)
-
转向中断/异常事件处理程序(软件)执行
- 进一步保护现场
- 执行相关处理代码
- 调度(可选)
- 恢复现场
-
恢复现场(硬件)
4.进程
**进程(process)**是一个可并发执行的具有独立功能的程序关于某个数据集合的一次执行过程,也是操作系统进行资源分配和保护的基本单位。
进程的性质:
- 共享性
- 动态性
- 独立性
- 制约性
- 并发性
进程的状态与转换:
- 三态模型
- 五态模型
-
具有挂起状态的七态模型*
5.关于进程的原语
(1)进程的创建
-
fork
派生,父子进程关系。Linux系统的fork采用copy_on_write技术,开始时子进程并不复制父进程的全部地址空间,而是以只读方式共享相同数据副本,仅当父子进程有一方执行写操作时数据才被复制和修改,此时父子进程才拥有各自的数据副本。
若fork成功,向父进程返回子进程ID,向子进程返回0,否则返回负值。
-
clone
克隆,对等关系。
-
vfork
与fork不同的是,vfork所创建的子进程完全运行在父进程的地址空间上,子进程对虚拟空间任何数据的修改同样可为父进程所见,但用vfork()函数创建子进程后,父进程将被阻塞,直到子进程执行exit()或exec()。
主要内容:
- 申请PCB
- 分配进程映像空间
- 分配资源
- 将进程内容装入分配空间
- 初始化PCB,分配唯一标识
- 加入就绪队列,或投入运行
- 通知操作系统其他模块
(2)进程的阻塞与唤醒
-
wait,waitpid,sleep…
-
进程阻塞内容
保存现场到PCB
修改进程状态(运行→等待)
将PCB加入相应等待队列
转入进程调度程序,调度其他进程 -
进程唤醒内容
从相应等待队列中取出PCB
修改进程状态(等待→ 就绪)
PCB加入就绪队列
(3)进程撤销(终止)
- exit
- 原因:完成、出现严重异常
- 主要内容:
- 根据进程标识号,找到相应的PCB
- 将该进程资源归还给父进程或系统
- 若有子进程,则要撤消其所有子(孙)进程
- PCB出队,将PCB归还PCB池
6.线程
-
进程:
操作系统中进行保护和资源分配的基本单位 -
线程:
- 操作系统中能够独立执行的实体,是处理器调度分配的基本单位
- 轻量级进程
- 同一进程中的所有线程共享进程获得的主存空间和资源
-
三种线程实现方式:
内核级实现的缺点
- 优点:能够在多个处理器上同时执行多个线程;某个进程中一个线程被阻塞,不会影响其他线程的运行
- 缺点:线程间的切换代价高,需要涉及两次模式切换
用户级实现的优缺点
- 优点:线程切换不涉及模式切换(代价小),调度算法的选择较灵活
- 缺点:同一进程的多个线程不能同时在多个处理器上运行;一个线程的阻塞将导致整个进程的阻塞;非抢占式调度
混合型实现的优缺点:
-
优点:设计得当,将可结合前两者的优点,并避开其缺点
-
缺点:设计不当,将产生更差的效果
7.处理器调度
-
高级调度:又称作业调度、长程调度,在多道批处理操作系统中从输入系统的一批左右中按照预定的调度策略挑选若干作业进入内存,为其分配所需资源并创建对应作业的用户进程。
高级调度将控制多道程序的道数。
-
中级调度:又称平衡调度,中程调度,根据内存资源情况决定内存中所容纳的进程数目,并完成外存和内存中的进程对换工作。
-
低级调度:又称进程调度/线程调度、短程调度,根据某种原则决定就绪队列中的哪个进程/线程获得处理器,并将处理器出让给它使用。
8.调度算法
(1)考虑因素和评价标准
调度算法考虑/评价的主要因素:
- 资源利用率
- 响应时间
- 周转时间:
- 作业提交开始到作业完成的时间
- 平均周转时间、平均带权周转时间
- 吞吐率
- 公平性
(2)几种典型调度算法
-
先来先服务:按照作业进入系统的作业后备队列的先后次序挑选作业,先进入系统的作业优先被挑选。
-
优点:
实现简单
-
缺点:
不利于短作业而优待长作业
效率低
-
-
最短作业算法SJF:以进入系统的作业所要求的CPU时间长短为标准,总是选取时间最短的作业投入运行
-
优点:
实现简单
效率高 -
缺点:
实际系统中,往往很难预测作业的运行时间
导致长作业等待时间过长,甚至出现“饥饿”现象
-
-
最短剩余时间优先SRTF:每次调度时,总选择预测剩余运行时间最短的作业优先运行
-
优点:
效率相对较高
-
缺点
调度频繁
与最短作业优先类似
-
-
最高响应比优先算法HRRF:在FCFS和SJF之间的折中,既考虑作业的等待时间,而考虑作业的运行时间
响应比=作业响应时间/作业估计计算时间- 优点:
防止了饥饿发生
- 优点:
(3)几个典型的低级调度算法
-
先来先服务
-
时间片轮转调度
-
优先数调度
-
动态优先数调度
-
最短进程优先
-
多级反馈队列调度
-
保证调度
-
彩票调度
-
实时调度与调度算法
对于周期事件,判断系统任务是否可调度的数学公式:
C 1 / P 1 + C 2 / P 2 + … + C m / P m < = 1 C_1/P_1 + C_2/P_2 + … + C_m/P_m <= 1 C1/P1+C2/P2+…+Cm/Pm<=1
其中m为事件总数,Ci为某个事件的处理时间,Pi为事件发生的周期。
三、并发控制
1.信号量和PV操作
- 信号量是用来解决进程/线程之间的同步互斥问题的一种通信机制,它表示代表某一类资源。
- 信号量的pv操作
p操作:对信号量减1,若结果大于等于0,则进程继续,否则执行p操作的进程被阻塞等待释放。
v操作:对信号量加1,若结果小于等于0,则唤醒队列中一个因为p操作而阻塞的进程。
2.管程
- 管程的定义:
管程是一种特殊的软件模块,它由下面的部分组成:- 局部于管程的共享数据结构说明;
- 对该数据结构进行操作的一组过程;
- 对局部于管程的共享设置初始值的语句;
- 管程有一个名字。
- 管程的基本特征:
- 局部于管程的数据只能被局部于管程的过程所访问;
- 一个进程只有通过调用管程内的过程才能进入管程访问共享数据;
- 每次仅允许一个进程在管程内执行某个内部过程。
更为详细的关于管程内容请参照课本。
- 下面是课本上Hoore管程的具体实现:
#include <iostream>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#include <stdio.h>
using namespace std;
//通过宏定义P、V操作
#define P(sem) \
sem_wait(sem);
#define V(sem) \
sem_post(sem);
typedef sem_t Semaphore;
typedef struct InterfaceModule
{
Semaphore mutex; //进程调用管程之前使用的互斥信号量
Semaphore next; //发出Signal()操作的进程挂起自己的信号量
int next_count; //在next上等待的进程数
InterfaceModule() //默认构造函数
{
sem_init(&mutex, 0, 1);
sem_init(&next, 0, 1);
next_count = 0;
}
~InterfaceModule() //析构函数,销毁信号量
{
sem_destroy(&mutex);
sem_destroy(&next);
}
} InterfaceModule;
void Enter(InterfaceModule &IM)
{
P(&(IM.mutex)); //互斥进入管程
}
void Leave(InterfaceModule &IM)
{
if (IM.next_count > 0) //判断有否发出Signal()操作的进程
{
IM.next_count--; //等待在next上的进程数减1
V(&(IM.next)); //释放一个挂起在next上的进程
}
else
{
V(&(IM.mutex)); //否则开放管程
}
}
void Wait(Semaphore &x_sem, int &x_count, InterfaceModule &IM)
{
x_count++; //等待资源的进程数加1,x_count初始化为0
if (IM.next_count > 0) //判断有否发出Signal()操作的进程
{
IM.next_count--; //等待在next上的进程数减1
V(&(IM.next)); //释放一个挂起在next上的进程
}
else
{
V(&(IM.mutex)); //否则开放进程
}
P(&(x_sem)); //等待资源的进程阻塞自己,x_sem初始化为0
}
void Signal(Semaphore &x_sem, int &x_count, InterfaceModule &IM)
{
if (x_count > 0) //判断是否有等待资源的进程
{
x_count--; //等待资源的进程数减1
IM.next_count++; //发出Signal()操作的进程数加1
V(&(x_sem)); //释放一个等待资源的进程
P(&(IM.next)) //发出Signal()操作的进程阻塞自己
}
}
3.死锁
(1)死锁产生的条件
- 互斥条件
- 占有和等待条件
- 不剥夺条件
- 循环等待条件
(2)死锁避免——银行家算法
数据结构
- Avaliable:可利用资源向量。这是一个含有m个元素的数组,每个元素代表一类可利用资源数目,其初值是系统中所配置的该类全部可用资源数目,其数值随该类资源的分配和回收而动态地改变。
- Max:—最大需求矩阵。这是一个m*n的矩阵,它定义了系统中n个进程中的每一个进程对n类资源的最大需求。
- Allocation:—分配矩阵。这是一个m*n的矩阵,它定义了当前系统的n个进程得到每一类资源的数目。
- Request:—请求向量。这是一个含有m个元素的向量,它表示进程i对各类资源的需求情况。
- Need:—需求矩阵。这是一个n*m的矩阵,它定义了当前系统的n个进程要想完成工作,还需要各类资源的数目。
算法步骤:
1、检查此次申请是否超过了之前声明的最大需求数
2、检查此时系统剩余的可用资源是否还能满足这次请求
3、试探着分配,更改数据结构
4、用安全性算法检查此次分配是否会导致系统进入不安全状态
例题:
系统有A, B, C 三类资源,总数量分别为(8, 10, 11)。系统中有5个进程分别为P0, P1, P2, P3和P4,其资源的占有和最大需求情况如下表所示:
Process Allocation Claim A B C A B C P0 2 0 2 4 3 4 P1 1 2 2 2 2 5 P2 0 3 3 1 3 4 P3 2 4 1 3 6 2 P4 2 0 1 3 1 3
1.系统是否处于安全状态?
2.若P4请求资源(1, 0, 2),系统是否能满足其请求,为什么?
第一问:
答:是安全的。先列出各个进程剩余需求序列
(
N
e
e
d
P
i
0
,
N
e
e
d
P
i
1
,
N
e
e
d
P
i
2
)
(Need_{P_i0},Need_{P_i1},Need_{P_i2})
(NeedPi0,NeedPi1,NeedPi2),其中
N
e
e
d
P
i
j
=
C
l
a
i
m
P
i
j
−
A
l
l
o
c
a
t
i
o
n
P
i
j
Need_{P_ij}=Claim_{P_ij}-Allocation_{P_ij}
NeedPij=ClaimPij−AllocationPij:
Process | Need |
---|---|
A B C | |
P0 | 2 3 2 |
P1 | 1 0 3 |
P2 | 1 0 1 |
P3 | 1 2 1 |
P4 | 1 1 2 |
然后每次都按照
P
0
→
P
4
P_0 \to P_4
P0→P4的顺序遍历挑选能够满足的进程,满足其要求,流程图如下:
可以看到存在进程序列
{
P
2
,
P
1
,
P
0
,
P
3
,
P
4
}
\{P2,P1,P0,P3,P4\}
{P2,P1,P0,P3,P4}满足安全性的要求。所以此刻系统是安全的。
第二问:
答:不可以。如果这时再满足
P
4
P4
P4的请求,剩余资源序列为
(
0
,
1
,
0
)
(0,1,0)
(0,1,0),无法再满足其他进程的需求。而同时
P
4
P4
P4由于仍然未达到其最大需求,所以它并不会归还资源。所以之后系统没有再可以满足其他任意进程的资源可供分配,而所有进程也不会归还资源给系统,进入死锁状态,导致系统不再安全,所以是不可以的。
(3)死锁检测
资源分配图:
死锁检测算法:
四、存储管理
请求分页式存储管理
典型的局部页面替换算法
-
最佳页面替换算法
调入一页而必须淘汰一个旧页时,所淘汰的页应该是以后不再访问的页或距现在最长时间后再访问的页。
Belady算法,作为衡量一个具体的可实现的页面替换算法优劣的依据。 -
随机页面替换算法
要淘汰的页面是由一个随机数产生程序所产生的随机数来确定
特点:实现简单、效率低。
-
先进先出页面替换算法
总是淘汰最先调入主存(在主存中驻留时间最长)的那一页。
特点:实现简单、适合具有线性特征的程序,对其他特性程序效率不高 -
第二次机会页面替换算法
改进的FIFO算法,最近仍在使用的页面被当作重新调入的页面处理
实现:FIFO算法与页表中的“引用位”结合使用
特点:效率较高,实现相对简单 -
时钟页面替换算法
基本思想等同于第二次机会页面替换算法,实现上存在差异
实现:使用环形队列,而非标准队列 -
最近最少用页面替换算法
当发生缺页中断时,检查指针指向位置的页面:
1)当页面引用位为0时,替换该页面;
2)当页面引用位非0时,对该引用位置0,指针累进
典型的全局页面替换算法
-
全局最佳页面替换算法
进程在 t 时刻发生缺页,则把该页面装入一个空闲页框。每次访问,均检查在内存中的所有页面引用情况,如果页面在时间间隔(t, t+τ)内未被引用,则移出该页面。
-
工作集模型和工作集置换算法
- 工作集,为确保每个进程每一时刻能够执行下去,在物理存储器中必须有的最少页面集合。(Denning, 1968)
- 根据工作集的大小分配主存块,以保证工作集所需要的页面能够进入主存。(可变分配)
- 为避免系统发生抖动,应该限制系统内的作业数量,使它们的工作集总尺寸不超过主存块总数。
程在 t 时刻发生缺页,则把该页面装入一个空闲页框。每次访问,均检查在内存中的所有页面引用情况,如果页面在时间间隔(t -T, t)内未被引用,则移出该页面。
通过页面被引用的历史情况来预估未来。
(和上一个很像,都是超时淘汰机制,主要是淘汰页面的时机在每次访问的时候) -
老化算法:
例如,时间间隔T定为1000次存储器引用,页面p在时刻t+0时寄存器为“1000”,在时刻t+1000时寄存器为“0100”,在时刻t+2000时寄存器为“0010”,在时刻t+3000时寄存器为“0001”,在时刻t+4000时寄存器为“0000”,此时,页面p被移出工作集
-
时间戳算法
若t_off > t_max,把页面从工作集中移出
-
模拟工作集替换算法
-
缺页频率替换算法
根据连续的缺页之间的时间间隔来对缺页频率进行测量,每次缺页时,利用测量时间调整进程工作集尺寸。
如果本次缺页与前次缺页之间的时间超过临界值T,那么,所有在这个时间间隔内没有引用的页面都被移出工作集。(简记:每隔时间间隔T检查淘汰没在该间隔内用过的页面)
最佳页面尺寸估计
f ( p ) = s e / p + p / 2 f(p)=se/p+p/2 f(p)=se/p+p/2
p : p: p:页面大小
s : s: s:进程的平均大小
e : e: e:页表项大小
五、存储管理
驱动调度技术
-
先来先服务
根据请求到来次序先后提供服务。 -
最短时间优先调度算法
-
电梯调度算法
-
平均等待时间为盘片旋转一周所需的时间的一半。
-
提高磁盘I/O速度的一些方法:
- 提前读
- 延迟写
- 虚拟盘