知识框架:
——为何引入:多道程序下,允许多个程序并发执行,此时他们将失去封闭性,并具有间断性以及不可再现性的特征。引入进程,以便于更好的描述和控制多道程序的并发执行,实现现代OS的并发性和共享性(最基本的两个特性)
——系统用PCB来描述进程的基本情况和运行状态,进而控制和管理进程。由程序段、相关数据段和PCB三部分组成进程映像(即进程实体)
进程映像是静态的,进程则是动态的
——进程定义:进程是进程实体的运行过程,是系统进行资源分配和调度的独立单位。
状态转化图如下:
注意区别就绪状态和等待状态:
就绪状态仅缺少处理机,只要获得处理机资源就立即执行;等待状态是指需要其他资源(除了处理机)或等待某一事件。在分时系统的时间片轮转机制中,进程在运行中实际上是频繁的转换到就绪状态的;而其他资源(如外设)的使用和分配或者某一事件的发生(如I/O操作完成)相对时间较长,这样来看,区分很有必要。
1)进程的创建与终止
3)进程的阻塞与唤醒
4)进程切换
切换过程:
1:保存处理机上下文
2:更新PCB
3:进程PCB移入相应队列,如就绪、阻塞等队列
4:选择另一个进程执行,并更新其PCB。
5:更新内存管理的数据结构
5)恢复处理机上下文
——注意:进程切换与处理机模式切换是不同的,模式切换时,处理机逻辑上可能还在同一进程中运行。还有,”调度“与“切换”区别,调度是决策,切换是实际分配行为。一般,先有资源调度,后有进程切换。
进程的通信是指进程间的信息交换。PV操作是低级通信方式,高级通信是指以较高的效率传输大量数据的通信方式。主要分三类:
——为何引入:减少程序在并发执行时的时空开销,提高OS的并发性能
线程可理解为”轻量级进程“,是基本的CPU执行单元,是程序执行的最小单元,由线程ID、程序计数器、寄存器集合和堆栈组成。线程是进程中的一个实体,是被独立调度和分配的基本单元,线程不拥有系统资源,只拥有一点在运行时必不可少的资源 。
——引入线程之后,进程只作为处CPU以外系统资源的分配单位,线程则作为处理机的分配单元。一个线程内有多个进程,如果线程的切换在同一个进程内,则只需很少的时空开销
首先,同一进程或不同进程的线程都可以并发执行
1)线程是一个轻型实体
2)不同线程可以执行相同的程序
3)同一进程中的各个线程共享该进程拥有的资源
4)线程是处理机的独立调度单位,多个线程可以并发执行
5)线程同进程一样也具有生命周期
线程提出有利于提高系统并发性的理解:有了线程,线程切换时,进程可能切换,也可能不切换,一平均每次切换所需时空开销就小了。
分为用户级线程与内核级线程
1)多对一,即多个用户级线程映射到一个内核级线程,线程管理在用户空间完成
优点:效率高
缺点:当一个进程在使用内核服务时阻塞,整个进程都会阻塞;多个进程不能运行在处理机。
1)一对一,即一个用户级线程映射到一个内核级线程
不容易阻塞,但效率低
3)多对多,即n个用户级线程映射到m个内核级线程(m<=n)
特带:上述两模型折中,既克服了多对一并发度不高,又克服了一对一模型的一个用户进程占用太多内核级进程,开销太大的缺点。
本节框架:
处理机调度引入:合理的处理计算机软硬件资源
——在多道程序中,进程数量往往多于处理机个数,进程争夺处理机现象在所难免,因此要对处理机进行分配,就是从就绪队列中,按照一定算法(公平、高效)选择一个进程分配处理机给予运行,以实现程序的并发执行。
1)作业调度为进程活动做准备,进程调度使进程正常活动起来,中级调度则将暂时不能运行的进程挂起,中级调度又称内存调度,处于两者之间
2)调度频率从作业到内存到进程递减
3)进程调度是最基本的,不可缺少
说明:作业是用户提交的,进程则有系统自动生成。作业以用户任务为单位,进程以OS控制为单位
——进程调度和切换程序是OS内核程序,当请求调度事件发生后,才可能会运行进程调度程序,当调度了新的就绪进程后,才有可能进行进程间的切换。
不能立刻进行处理机调度的情况:
1)非剥调度夺方式
2)剥夺调度方式
说明:
1)高响应比优先调度算法、时间片轮转法、多级反馈队列调度,适用于分时系统;抢占式优先级调度算法适用于实时系统
2)时间轮转法是绝对可抢占的,此算法增加了系统开销,吞吐量和周转t不如批系统,但快速响应t使得用户和计算机交互,改善了人机环境,满足了用户需求。
知识框架:
定义:一次仅允许一个进程使用,如打印机,共享变量等
把访问临界资源的那段代码称为临界区
临界资源可划分四部分:
1)进入区,在此设置访问临界区的标志,防止其他进程同时进入
2)临界区,访问临界区的那段代码
3)退出区,将正在访问临界区的标志清除
4)剩余区
do{
entry section; //进入区
critical section; //临界区
exit section; //退出区
remainder section; //剩余区
}while(true);
同步是指为完成某种任务而建立两个或者多个进程,这些进程因为需要在某些位置上的协调他们的工作次序而等待、传递信息而产生的制约关系。
互斥是指当一个进程进入临界区使用临界资源时,另一个进程必须等待,当占用临界资源的进程退出临界区后,才允许另一进程访问此临界资源。
为禁止两个进程同时进入临界区,同步机制应该遵守以下规则:
1)空闲让进
2)忙则等待
3)有限等待
4)让权等待
1)单标志法
turn=0,则允许P0进入。
缺点:违背"空闲让进",两个进程必须交替进入临界区,若某个进程不再进入临界区,则另一个进程也无法进入临界区。
P0进程: P1进程:
while(turn); while(turn);
critical section; critical section;
trun=1; turn=0;
remainder section remainder section;
2)双标志先检查
优点:不用交替进入,可连续使用
缺点:违背“忙则等待”,Pi和Pj可能同时进入临界区,按1,2,3,4执行时,会同时进入临界区。即在检查对方flag之后和切换自己flag之前有一段时间,结果都检查通过
Pi进程: Pj进程:
while(flag[j]);1 while(flag[i]);2 //进入区
flag[i]=true; 3 flag[j]=true;4 //进入区
critical section; critical section; //临界区
flag[i]=false; falg[j]=false; //退出区
remainder section; remainder section; //剩余区
3)双标志后检查
缺点:可导致”饥饿“现象,当两个进程几乎同时想进入临界区,分别把自己的flag置true,并且检测对方状态,发现对方也想进入临界区,结果谁也进不了,从而“饥饿”
Pi进程: Pj进程:
flag[i]=true; flag[j]=true; //进入区
while(flag[j]); while(flag[i]); //进入区
critical section; critical section; //临界区
flag[i]=false; falg[j]=false; //退出区
remainder section; remainder section; //剩余区
4)Peterson‘s Algorithm。
优点:即可互斥访问,也不会“饥饿”
Pi进程: Pj进程:
flag[i]=true;turn=j; flag[j]=true;turn=i;
while(flag[j]&&turn==j); while(flag[i]&&turn==i)
critical section; critical section;
falg[i]=false; flag[j]=false;
remainder section; remainder section;
具体如下:考虑Pi进程,若设置flag[i]=true,表示Pi进程想进入临界区,同时turn=j,如果Pj已在临界区,则符合Pi内while条件,则Pi不能进入临界区。若Pj不在临界区,while不符合,则Pi顺利进入临界区。
1)中断屏蔽
CPU只有在中断时才引起进程切换
2)硬件指令方法
TestAndSet指令:
TST(Test And Set lock)伪代码
do{
......
while(TST(&lock));
critical section;
lock=false;
......
}while(true);
分析:
1)当进程退出临界区时置lock为false,会唤醒处于就绪状态的进程。
2)等待进入临界区的进程会一直停留在while(TST(&lock)循环中,不会主动放弃CPU,违反“让权等待”
1)整形信号量
被定义于表示资源个数的整型量S。当S<=0时,会循环测试,未遵循“忙则等待”
2)记录型信号量(遵循“让权等待”)
数据结构如下:
typedef struct{
int value;
struct process *L;
} semaphore;
记录型信号量S中value意义:
1)初值表示系统中某类资源的个数
2)S.value<0,表示系统已经没有可用的此类资源
3)S.value<0,其绝对值表示S.L中因等待该资源而阻塞的进程个数
引入:为了解决临界区分散带来的管理和控制问题
组成:
1)局部于共享结构数据说明
2)对该组数据结构进行操作的一组过程
3)对局部于管程的共享数据设置初始值的语句
emm,很像一个抽象类,有木有
1)生产者和消费者
semaphore mutex=1;
semaphore empty=n; //空缓冲区
semaphore full=0; //初始化缓冲区为空
producer(){
while(true){
prodece an item in nextp;
P(empty); //用什么,P一下
P(mutex);
add next to buffer;
V(mutex);
V(full); //提供什么,V一下
}
}
consumer(){
while(true){
P(full);
P(mutex);
remove an item from buffer;
V(mutex);
V(empty);
consume the item;
}
}
注意:对empty和full变量的P操作必须放在对mutex的P操作之前,否则有可能出现死锁。(死锁后面介绍)
2)读者——写者问题
3)哲学家进餐问题(5个哲学家为例)
思路:当一个哲学家两边都有筷子可用时,才允许他抓起筷子
semaphore chopstick[5]={1,1,1,1,1};
semaphore mutex=1;
Pi(){
do(){
P(mutex);
P(chopstick[i]);
P(chopstick[(i+1])%5);
V(mutex);
eat;
V(chopstick[i]);
V(chopstick[(i+1)%5]);
think;
}while(true);
}
4)吸烟者问题
问题描述:一个系统中有三个吸烟者进程和一个供应者进程。每个抽烟者不停卷烟并抽掉。抽烟者需要三种材料:烟草、纸和胶水。三个抽烟者中,1号有烟草,2号有纸,3号有胶水,供应者进程无限提供这三种材料,供应者每次将两种材料放桌上,拥有剩下那种材料的抽烟者卷烟并抽掉它,并给提供者一个信号告诉其完成了,供应者就放另外两种材料在桌上,一直重复这个过程。
int random; //存储随机数
semaphore offer1=0; //烟草和纸组合
semaphore offer2=0; //烟草和胶水组合
semaphore offer3=0; //纸和胶水组合
semaphore finish=0; //定义信号量表示烟是否抽完
process P1(){
while(true){
random=任取随机数;
random=random%3;
if(random==0)
V(offer1); //提供烟草和纸
else if(random==1)
V(offer2); //提供烟草和胶水
else
V(offer3); //提供纸和胶水
任意两种材料放桌上;
P(finish);
}
}
process P2(){ //拥有烟草者
while(1){
P(offer3);
拿纸和胶水,卷烟,抽烟;
V(finish);
}
}
process P2(){ //拥有纸者
while(1){
P(offer2);
拿烟草和胶水,卷烟,抽烟;
V(finish);
}
}
process P2(){ //拥有胶水者
while(1){
P(offer1);
拿烟草和纸,卷烟,抽烟;
V(finish);
}
}
知识框架:
——所谓死锁是指多个进程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程将无法向前推进。
1)系统资源的竞争
2)进程的推进顺序非法
3)死锁产生的必要条件
**互斥条件
**不可剥夺条件
**请求和保持条件
**循环等待条件:
1)死锁预防
2)死锁避免
3)死锁的检测于解除
几种策略的比较:
破坏四个必要条件之一即可
1)破坏互斥
不太可行,并且有的场合需要保护这种互斥性
2)破坏不可剥夺条件
这种方法常用于易于保护和恢复的资源,如CPU的寄存器及内存资源,一般不能用于打印机之类的资源
3)破坏请求和保持条件
采用静态分配方法,一次申请所有需要资源,资源不足,不运行。一旦运行,资源一直归他所有。资源浪费严重,容易“饥饿”。
4)破坏循环等待条件
采用资源顺序分配法可实现。
在资源动态分配过程时,防止系统进入不安全状态,以避免死锁发生
所谓安全状态,是指系统按照某种进程推进顺序(P1、P2..Pn),为每个进程分配所需资源,直到满足进程对资源的最大需求,使每个进程都可顺利完成任务。此时P1、P2..Pn为安全序列。如果无法找到一个安全序列,则系统处于不安全状态
说明:不安全状态不一定死锁,但系统若处于安全状态,便可以避免死锁。
系统状态S死锁的条件是当且仅当S状态的资源分配图是不可完全化简的,该条件为死锁定理
1)资源剥夺法
2)撤销进程法
3)进程回退法