第一章 操作系统引论
一、操作系统(OS)的定义:
是计算机最基础的软件系统。他管理软硬件资源,控制程序执行,改善人机界面,合理组织计算机工作流程,为用户使用计算机提供良好的运行环境
二、操作系统目的
- 方便性
- 有效性
- 可扩充性
- 开放性
三、发展过程
①人工操作方式:用户独占全机,CPU等待人工操作。
②脱机输入输出方式:事先将装有用户程序和数据的纸带装入纸带输入机,在外围机的控制下,把纸带上的数据输入到磁带上(类似于磁盘)。
当CPU需要时,从磁带将其高速地调入内存。反之类同。
- 优点:减少了CPU的空闲时间,提高了I/O速度。
③单道批处理系统:首先监督程序将磁带第一个作业装入内存,运行控制权在该作业,该作业处理完成时,控制权交回到监督程序,再由监督程序把磁带上的第二个作业调入内存。系统自动对作业成批处理。(内存始终只保持一道作业—单道批处理)。
- 缺点:内存浪费,不能充分利用系统资源。
④多道批处理系统:用户所提交的作业先存放在外存,排成一个“后备队列”,再由作业调度程序按一定的算法从队列选择若干作业调入内存,使他们共享CPU和系统中的各种资源。
- 优缺点:资源利用率提高,系统吞吐量大,平均周转时间长,无交互能力。
⑤分时系统:在一台主机上连接了多个带有显示器和键盘的终端,同时允许多个用户通过自己的终端,以交互方式使用计算机,共享主机中的资源。因此,作业直接进入内存,采用轮转运行方式,系统配置一个多路卡(实现分时多路复用),及时接收用户终端命令(数据)。
- 特征:多路性、独立性、及时性、交互性。
⑥实时系统:系统能及时响应外部事件的请求,在规定的时间内完成对该事件的处理,并控制所有实时任务的协调一致的运行。
- 特征:多路性(周期性信息采集,多个对象或执行机构进行控制)、独立性、及时性、交互性、可靠性(多级容错措施)。
1.1 操作系统的基本特性
一、并发
并行性:两个或多个事件在同一时刻发生
并发性:两个或多个事件在同一时间间隔发生
二、共享
互斥共享方式:在一段时间内只允许一个进程访问的资源称为临界资源或独占资源。
同时访问方式:允许在一段时间内由多个进程同时对它们进行访问。
三、虚拟
是指通过某种技术(虚拟技术)将一个物理实体变为若干个逻辑上的对应物。
在操作系统中,虚拟的实现主要是通过分时使用的方法。
四、异步性
(进程以不可预知的速度向前推进)。
1.2 操作系统的主要功能
处理机管理功能
- ①进程控制:创建和撤销进程,分配资源、资源回收,控制进程运行过程中的状态转换。
- ②进程同步:为多个进程运行进行协调。进程互斥(为每个临界资源配置一把锁)、进程同步。
- ③进程通信:实现相互合作之间的进程之间的信息交换。
- ④调度:作业调度,进程调度。
存储器管理的主要任务:
为多道程序的运行提供良好的环境,方便用户使用存储器,提高存储器的利用率,并能从逻辑上扩充内存。
‘功能:
- ①内存分配:静态分配、动态分配。
- ②内存保护:确保每道用户程序都只在自己的内存空间内运行,彼此互不干扰。一种比较简单的内存保护机制是设置两个界限寄存器。
- ③地址映射:将地址空间中的逻辑地址转换为内存空间中与之对应的物理地址。
- ④内存扩充:借助于虚拟存储技术,逻辑上扩充内存容量。
设备管理功能:
设备管理的主要任务:
完成用户进程提出的I/O请求,为其分配所需的I/O设备;提高CPU和I/O设备的利用率,提高I/O速度,方便用户使用I/O设备。
功能:
- ①缓存管理:缓和CPU和I/O设备速度不匹配的矛盾。
- ②设备分配:根据用户进程I/O请求、系统现有资源情况以及按照某种设备的分配策略,为之分配其所需的设备。
- ③设备处理:用于实现CPU和设备控制器之间的通信。
文件管理的主要任务:
对用户文件和系统文件进行管理,方便用户使用,并保证文件的安全性。
- ①文件存储空间的管理:为每个文件分配必要的外存空间,提高外存的利用率,并能有助于提高文件系统的存、取速度。
- ②目录管理:为每个文件建立其目录项,并对众多的目录项加以有效的组织,以实现方便的按名存取,即用户只须提供文件名便可对该文件进行存取。
- ③文件的读/写管理和保护
操作系统与用户之间的接口:用户接口、程序借口
1.3 内核分类
- 1、单内核,也称为宏内核—Linux
- 2、微内核–QNX,鸿蒙
- 3、混合内核
第二章 进程管理
2.1 进程的概念
进程实体:由程序段、相关的数据段和PCB组成,所谓创建和撤销进程实际是对其中的PCB的创建和撤销。(PCB:进程控制块Process Control Block)
进程的特征:动态性、并发性、独立性、异步性
进程的三种基本状态:就绪状态、执行状态、阻塞状态(阻塞典型事件:请求I/O,申请缓冲空间等)。
挂起状态:进程处于静止状态,暂停执行(执行状态下挂起),暂不接受调度(就绪状态下挂起)。
进程的五种基本状态及其转换图。
具有创建、终止和挂起状态的进程状态图。
2.2.1进程描述
进程控制块PCB
PCB中记录了操作系统所需的、用于描述进程的当前情况以及控制进程运行的全部信息。是操作系统中最重要的记录型数据结构。
进程控制块中的信息:进程标识符、处理机状态、进程调度信息、进程控制信息。
进程控制块的组织方式:链接方式、索引方式。
PCB包括如下:
进程名、特征信息、进程状态信息、调度优先权、通信信息、现场保护区(上下文)、资源需求、分配和控制方面的信息、进程实体信息、族类关系、其他信息。
每个进程都有唯一的PCB
PCB是进程存在的标志(你的身份证是你存在的标志)
2.2.2 进程队列
- 线性方式
- 有最大数的限制,操作麻烦
- 链接方式
- 索引方式
2.2.3 进程控制
进程控制一般是由OS的内核中的原语来实现的
操作系统内核的功能:
- 中断处理
- 时钟管理
- 原语操作(原子操作)
- 不可分割,执行过程不允许中断,所以一般都是执行最关键的操作用原语
2.2.4 进程的创建
- ①申请空白PCB。
- ②为新进程分配资源。
- ③初始化进程控制块。
- ④将新进程插入就绪队列(如果进程就绪队列能够接纳新进程)。
进程的终止过程
- ①根据被终止进程的标识符,从 PCB 集合中检索出该进程的 PCB,从中读出该进程的状态。
- ②若被终止进程正处于执行状态,应立即终止该进程的执行,并置调度标志为真,用于指示该进程被终止后应重新进行调度。
- ③若该进程还有子孙进程,还应将其所有子孙进程予以终止,以防它们成为不可控的进程。
- ④将被终止进程所拥有的全部资源,或者归还给其父进程,或者归还给系统。
- ⑤将被终止进程(PCB)从所在队列(或链表)中移出,等待其他程序来搜集信息。
进程的阻塞与唤醒引起进程阻塞或唤醒的事件:
- 1、向系统请求共享资源失败
- 2、等待某种操作的完成
- 3、新数据尚未到达
- 4、等待新任务的到达
进程阻塞过程(主动行为)
进程通过调用阻塞原语block将自己阻塞
唤醒:唤醒原语wakeup
wakeup执行的过程是:首先把被阻塞的进程从等待该事件的阻塞队列中移出,将其PCB中的现行状态由阻塞改为就绪,然后再将该PCB插入到就绪队列中。
2.2.5Linux进程控制常用函数
-
fork()、
- 作用:创建一个新进程。
- 系统调用格式: pid=fork( )
- 参数定义:int fork( )
- 返回值意义:
- 0:在子进程中,pid变量保存的fork( )返回0,表示当前进程是子进程。
- 大于0:在父进程中,pid变量保存的fork( )返回值为子进程的id值(进程唯一标识符)。
- -1:创建失败。
- 如果fork( )调用成功,它向父进程返回子进程的PID,并向子进程返回0,即fork( )被调用了一次,但返回了两次。此时OS在内存中建立一个新进程,所建的新进程是调用fork( )父进程的副本,称为子进程。子进程继承了父进程的许多特性,并具有与父进程完全相同的用户级上下文(即程序)。父进程与子进程并发执行。
-
exec()
- exec( )系列函数用新进程取代了原来进程,并将一个可执行的二进制文件覆盖在新进程的用户级上下文的存储空间上。因此,如果exec( )调用成功,调用进程将被覆盖,然后从新程序的入口开始执行。新进程的进程标识符id 与调用进程相同。
-
wait()
-
exit()
fork()
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
main()
{ pid_t pid;
pid=fork();
printf("Hello,World!\n");
}
exec()
#include<stdio.h>
#include<unistd.h>
#include <stdlib.h>
main( )
{
execl("/bin/ls","ls","-l","../",NULL);
printf("hello,world!\n");
exit(0);
}
结果没有打印出hello world,说明没有执行下面的语句,原因是execl产生了新进程覆盖了原来的进程。
exec()和fork()的联合使用
因为使用fork虽然可以创建一个新的进程,但是子进程是父进程的副本,而exec可以创建一个新的进程,但会覆盖原来的进程,所以我们希望创建新进程的同时又不会覆盖父进程,可以采用exec和fork结合的方式
用fork( )建立子进程,然后在子进程中使用exec( ),这样就实现了父进程与一个与它完全不同子进程的并发执行。
#include<stdio.h>
#include<unistd.h>
#include <stdlib.h>
main( )
{
int pid;
pid=fork( ); /*创建子进程*/
switch(pid)
{
case -1: /*创建失败*/
printf("fork fail!\n");
exit(1);
case 0: /*子进程*/
execl("/bin/ls","ls","-l","../",NULL);
printf("this is son!\n");
exit(1);
default: /*父进程*/
printf("this is father !\n");
exit(0);
}
}
2.3 线程(轻型进程)
进程:使得多个程序能够并发执行,提高资源利用率和吞吐量
线程:减少程序在并发执行时所付出的时空开销,使得OS具有更好的并发性
线程—作为调度和分派的基本单位
- 进程—资源分配的最小单位
- 线程—程序执行的最小单位
线程应用场景:
- 需要有多功能并发
- 改善交互性
- 多核CPU,充分发挥多核CPU的性能
线程的两种实现方式:
- 1、用户级线程ULT(User Level Threads)——线程整个放在在用户空间,内核对线程一无所知,只对进程管理。
- 2、内核支持线程KST(Kernel Supported Threads) ——内核知道线程的存在,并对它们进行管理。内核调度时,以线程为基本单位。
用户级线程ULT下,调度以进程为单位进行,各个进程轮流执行一个时间片。
而内核支持线程KST下,调度以线程为单位进行,各个线程轮流执行一个时间片。
Linux中线程基本操作的相关函数
- pthread_creat:创建线程。
- pthread_exit:线程退出
- pthread_join:线程之间的同步。类似进程之间的同步函数wait。函数pthread_join将当前线程挂起,等待另一线程的结束
2.3.1 进程的同步和互斥
进程间的相互关系主要有三种:同步、互斥、通讯
进程的同步关系:
若干合作进程为了完成一个共同的任务,需要相互协作运行进度,一个进程开始之前需要要求另外一个进程已经完成某个操作,否则前面的进程只能等待。
进程的互斥关系
多个进程由于共享了独占性资源(一次只能有一个进程占用,比如打印机等),必须协调各进程对资源的存取顺序,确保不会有两个或两个以上的进程占用。(谁先占,那么就只能一个人占,其他人就不能进来)互斥和资源共享相关
资源称为临界资源,存取操作区域称为临界区
互斥关系也属于同步关系,是一种特殊的同步
临界资源: 一次仅允许一个进程使用的共享资源称为临界资源
临界区: 每个进程中访问临界资源的那段代码称为临界区
临界区进入准则
- 单个入区
- 独自占用
- 尽快退出
- 落败让权:如果进程不能进入临界区,则让出CPU,以免出现忙等现象
互斥实现方式(临界区访问方式)
1.硬件同步机制
1、关中断
- 是实现互斥的最简单的方法之一
- 原理:由于禁止中断,时钟中断也被禁止
- 缺点:
- 滥用中断权利可能会导致严重的后果
- 关中断的时间过长,会影响系统效率
- 不适用多CPU系统,因为在一个CPU上关中断并不能防止进程在其他CPU上执行相同临界区的代码
2、TSL指令、SWAP指令
- 利用硬件指令以实现互斥的方法
- 该指令的执行过程不能被分割
- 仍然是不符合让权等待原则
boolean TSL(boolean *lock){
boolean old;
old=*lock;
*lock=TRUE;
return old;
}
# *lock=True 表示资源正在被占用 为FALSE表示资源空闲
2.软件方式
(1)、锁机制
- 原理:设置一个标志锁,表明临界区可用还是不可用
- 注意:锁机制不满足让权等待
#上锁
上锁原语 lock(W):
while(W==1);
w=1;
#开锁原语unlock(W ):
W=0;
(2)、信号量机制(P(wait(S))测试、V操作(signal(S)增加)
typeof struct {
int value; //资源数目
struct pross_control_block *list; //进程链表指针
}semaphore;
//p操作
P(semaphore * S){
S->value--;
if(S->value<0) block(S->list);
}
//V操作
V(semaphore *S){
S->value++;
if(S->value<=0) wakeup(S->list);
}
AND型信号量
有的应用场景,是一个进程往往需要获得两个或更多的共享资源后才能执行任务的情况。假设现在有两个进程A和B,他们都要求访问共享数据D和E,共享数据应作为临界资源。
注意:下面的wait相当于P操作;假设Dmutex和Emutex的初始值都为1
process A:
wait(Dmutex);
wait(Emutex);
process B:
wait(Emutex);
wait(Dmutex);
上面的程序明显是有问题的,因为如果A和B同时申请资源,这个时候AwaitD,BwaitE,这个时候,A没法继续向下执行,B也没法继续向下执行(资源各有一部分被双方占用)——死锁
AND同步机制的基本思想
将进程在整个运行过程中所需要的所有资源,一次性的全部分配给进程,待使用完毕后一起释放。要么全分配,要么一个都不分配 为Swait和Ssingnal操作
Swait(S1,S2,...Sn){ // P操作
while(TRUE){
if(Si>=1&&....&&Sn>=1){
for(i=1;i<=n;i++) Si--;
break;
}
else{
//将进程挂在第i个Si<=0的等待队列中,并把各个值恢复原值
}
}
}
信号量集
信号量的应用
1、利用信号量实现互斥
为该资源设置一个互斥信号量mutex,并设置其初始值为1.
main(){
//信号量mutex的初始值为1
int mutex=1;
cobegin //并发
Pa();
Pb();
Pc();
coend;
}
2、利用信号量P,V实现同步关系
基本思路:
- 定义有意义的信号量S,设置合理的初值
- 当某进程的运行条件不满足时,利用P操作暂停当前执行
- 当满足时,利用V操作释放信号量,从而使被暂停的进程得以被唤醒继续
P{
S1;
V(signal);
}
V{
P(signal);
S2;
}
例子2:司机VS售票员
司机的进程
起步;
行驶;
停车;
售票员的进程
关门;
售票;
开门;
同步要求:
1、只有售票员关门后,司机才能起步
2、只有司机停车之后,售票员才可以开门
司机的进程
while(TRUE){
P(signal1);
起步;
行驶;
停车;
V(signal2);
}
售票员的进程
while(TRUE){
关门;
V(signal1);
售票;
P(signal2);
开门;
}
2.3.2 经典进程的同步问题
生产者-消费者“问题
生产者在生产,消费者消费产品,在他们之间设置了一个具有N个缓冲区的环形缓冲池,生产者将生产的产品放入一个缓冲池中,消费者进程可以从缓冲区中取走产品进行消费:
需要满足的同步条件:
- 1、不能向满缓冲区存产品
- 2、不能向空缓冲区存产品
- 3、每个时刻仅允许一个生产者或一个消费者存取1个产品
分析:因为两个进程每次只允许一个进行存取操作,所以先用P,V互斥一下,还有,不能向满的存产品,不能向空的取产品,换而言之,当取时,需要看这个产品还有没有,当存的时候,需要判断是否已满。
- 设缓冲区的编号为0-N-1,in和out分别是生产者进程和消费者进程使用的指针,指向可用的缓冲区,初始值为0
- 设置三个信号量
- full 表示放有产品的缓冲区,初始值为0
- empty 表示可供使用的缓冲区,初始值为N
- mutex 互斥信号量,初始值为1,保证任何时候只有一个进程使用缓冲区
int in =0,out=0;
semaphor mutex=1,empty=N,full=0;
生产者进程Producer{
whlie(True){
P(empty);
P(mutex);
产品送往buffer(in);
in=(in+1)mod N;
//以N为模
V(mutex);
V(full);
}
}
消费者进程Consumer{
P(full);
P(mutex);
从buffer(out)中取出产品;
out=(out+1)mod N;
//以N为模
V(mutex);
V(empty);
}
利用AND信号量解决生产者消费者问题
用Swait(empty,mutex)来代替P(empty)和P(mutex);
用Ssignal(mutex,full) 来代替V(mutex)和V(full)
用Swait(full,mutex)代替P(full)和P(mutex)
用Ssignal(mutex,empty)代替V(mutex)和V(empty)
哲学家进餐问题
一张圆桌,五个碗五支筷子,五个哲学家的生活方式是交替进行思考用餐,平时,一个哲学家进行思考,饥饿时便试图取其左右两边的筷子,只有拿到两双筷子才能进餐,进餐完毕,放下筷子继续思考。
分析步骤:
临界资源:筷子
进程:五个进程(五个哲学家)
临界区代码:吃饭
利用记录型信号量
因为每一支筷子不可能同时两个哲学家拿到,所以筷子之间是互斥的。可以用一个信号量表示一只筷子,由这五个信号量构成信号量数组:
为了防止死锁,需要同时拿起左边和右边的筷子才能吃饭(为了防止同时有5个人拿起左边的筷子造成死锁)
semaphpore chopstick[5]={1,1,1,1,1} //各信号量初始为1
do{
....
//思考
Swait(chopstick[(i+1)%5],chopstick[i]);
...
//进餐
Signal(chopstick[(i+1)%5],chopstick[i]);
}while(TRUE);
读者和写者问题
只读文件进程:reader进程
可写进程:writer进程
典型例子:航班预订系统的数据库
一个文件,很多进程都可以去读,但是写的时候只能有一个写(进程与进程之间在写进程时是互斥的)
要求:
- 允许多个进程进行读操作
- 不允许writer和reader进程同时操作
- 不允许多个writer进程同时操作
//读者reader进程
while(TRUE){
P(mutex);
readcount++; //readcount也是作为临界资源,防止reader进程修改破坏
if(readcount==1)
P(wmutex);
V(mutex);
P(wmutex); //有写者就不能有读者
执行读操作
P(mutex);
readcount--;
if(readcount==0)
V(wmutex);
V(mutex);
}
//写者writer进程
while(TRUE){
P(mutex);
P(wmutex); //因为一次只能有一个写者
执行写操作
V(mutex);
V(wmutex);
}
利用信号量集机制解决读者-写者问题
假设最多有RN个读者同时读取。为此,又引入了一个信号量L,初始值为RN,通过执行wait(L,1,1)来控制读者数目。
mx表示写资源’
int RN;
semaphore L=RN,mx=1;
void reader(){
do{
Swait(L,1,1;mx,1,0);
....
进行读操作
Ssignal(L,1);
}while(TRUE)
}
void writer(){
do{
Swait(mx,1,1;L,RN,0);
...
进行写操作
Ssignal(mx,1);
}while(TRUE);
}
void main(){
cobegin
reader();
writer();
coend
}
打瞌睡的理发师问题
理发店里面有一个理发师一把理发座椅和几把座椅,等待理发的可以在上面等待
如果没有顾客到来,理发师就坐在理发椅上打瞌睡
有顾客到来,就唤醒理发师,如果顾客正在理发,该顾客可以坐在座椅上等待,如果座椅满座了,就到别处理发
分析:
理发师进程和顾客各有一个进程
理发师进程:开始工作,先看看有没有顾客,没就打瞌睡,如果有就被唤醒,进行理发,等待人数-1。因为理发师不停理发,所以使用while循环
顾客进程:每个顾客一个进程,所以有多个进程。每个进程中,如果顾客数超过座位数,就结束进程。否则等待。因为顾客理完发就走,因此不需要while循环
fefine CHAIRS 5
typedef struct{
int value;
struct PCB*list
}semaphore;
semaphore customers=0;
semaphore babers=0;
semaphore mutex=1;
int waiting =0;
void baber(){
while(TRUE){
P(customer); //如果没有顾客,打瞌睡
P(mutex); //互斥进入临界区
waiting---;
V(barbers); //一个理发师进行理发
V(mutex); //退出临界区
cut_hair(); //理发
}
}
void customer(){
P(mutex); //互斥进入临界区
if(waiting<CHAIRS){
waiting--;
V(customers); //若有必要,唤醒理发师
V(mutex);
P(barbers);
get_haircut();
}else{
V(mutex); //店里满人
}
}
第三章 死锁
3.1 死锁的概述
死锁定义为一组相互竞争资源或进行通信的进程间的“永久”阻塞。
3.2 资源问题
3.2.1 可重用性资源和消耗性资源
可重用性资源:可供用户重复使用多次的资源
每一个可重用性资源中的单元只能分配给一个进程使用,不允许多个进程共享
进程在使用可重用性资源时,需按照这样的顺序:
- 请求资源:如果请求失败,将被放进阻塞或循环队列等待
- 使用资源
- 释放资源
可消耗性资源(临时性资源)
它是在进程运行期间,由进程动态创建和消耗的
3.2.2 可抢占性资源和不可抢占性资源
可抢占性资源
某进程在获得这类资源后,该资源可以再其他进程或系统抢占。例如CPU内存属于可抢占性资源,这类资源不会引起死锁。
不可抢占性资源
一旦系统将资源分配给该进程后,就不能强行收回,只能在进程用完之后自行释放。典型例子:打印机
3.3 计算机系统中死锁形成原因
竞争不可抢占性资源引起死锁
竞争可消耗性资源引起死锁
进程推进顺序不当引起死锁:对资源进程申请和释放的顺序是否合法也会影响死锁。
3.4 死锁定义,必要条件和处理方法
3.4.1 死锁的定
如果一组进程中的每一个进程都在等待仅由该组进程中的其它进程才能引发的事件,那么该组进程是死锁的(Deadlock)。
3.4.2 产生死锁的必要条件
- 互斥条件:在一段时间内,某资源只能被一个进程使用。如果有其他进程申请使用该资源,需要等待。
- 请求和保持条件:进程必须至少保持一个资源,但如果又提出了新的资源申请,而该资源已经被其他进程占有,此时请求进程被阻塞,但对自己获得的资源不释放。
- 不可抢占条件:资源自己占有,使用完后再释放
- 循环等待条件:必然形成环路
3.4.3 处理死锁方法
3.4.3.1 预防死锁
主要是破坏产生死锁的后三个必要条件。
破坏请求和保持条件:当一个进程在请求资源时,他不能持有不可抢占资源,这通常通过下面两个协议保证:
- 第一种协议:所有进程开始运行之前,必须一次性申请其在整个运行过程中所需的全部资源。
- 若系统有足够的资源分配给该进程,便可以把其需要的所有资源分配给他。这样,在整个运行期间,就不会再提出资源要求,破坏了"请求"条件
- 如果系统缺少任何一个资源,都不会分配给进程,那么进程就会进入等待状态,在等待状态进程不会占用任何资源,破坏了保持条件
- 优点:简单,易行且安全
- 缺点:资源被严重浪费,严重恶化了资源的利用率
- 使进程经常会发生饥饿现象
- 第二种协议:运行一个进程只获取初期所需的资源后便开始运行。进程运行过程中再逐步释放已分配的全部资源,然后再请求新的所需资源。(不要吃着碗里的看着锅里的,如果要想从锅里拿食物,必须先将碗里的吃完之后再拿)
破坏不可抢占条件:当一个保持了某些不可抢占性资源的进程,提出新的资源请求而不能得到满足时,他必须释放已经保持的所有资源,待以后需要时再重新申请。
破坏“循环等待”条件:一个能保证“循环等待”条件不成立的方法是,对系统所有资源类型进行线性排序,并赋予不同的序号。
3.4.3.2 避免死锁
在资源分配过程中,防止系统进入不安全状态,避免发生死锁。目前常用此方法。
系统状态:安全状态和不安全状态
当系统处于安全状态时,可避免发生死锁。当系统处于不安全状态时时,可能进入死锁。
利用银行家算法避免死锁
3.4.3.3 检测和解除死锁
死锁的解除
- 抢占资源:从一个或多个进程中抢占足够的资源,分配给死锁的进程,以解除死锁状态。
- 通过回退执行实现恢复
- 终止进程
- 终止所有死锁进程
- 逐个终止进程:按照某种顺序,逐个地终止进程,直至有足够的资源,以打破循环等待,把系统从死锁状态解脱出来为止
3.4.3.4 对比三种方法
3.5饥饿和活锁的概念
饥饿的概念
- 某些进程所需的资源总是被别的进程占有或抢占。——饥饿或饿死
- 当等待时间给进程的推进和响应带来明显的影响时,就称发生了进程饥饿。当饥饿到一定程度的进程所赋予的任务即使完成也不再具有实际意义时,称该进程被饿死。
活锁的概念
- 活锁是指的是任务或者执行者没有被阻塞,由于某些条件没有满足,导致一直重复尝试—失败—尝试—失败的过程。处于活锁的实体是在不断的改变状态,耗尽CPU资源,使系统效能下降。活锁有可能自行解开。
例子:过桥问题,两个人都很谦让让对方先过