操作系统第二章总结

第二章

第一节

进程

一、进程的定义

PCB:进程控制块,系统为每个运行的程序配置一个数据结构,用来描述进程的各种信息
进程实体(镜像进程):简称进程,由程序段,数据段,PCB组成
创建进程实质上是创建进程实体中的PCB,撤销进程是撤销进程中的PCB,PCB是进程存在的唯一标志

进程的定义(强调动态性):

  1. 进程是程序的一次执行过程。
  2. 进程是一个程序及其数据在处理机上顺序执行时所发生的活动。
  3. 进程是具有独立功能的程序在数据集合上运行的过程,它是系统进行资源分配和调度的一个独立单位

引入进程实体后进程的定义
进程是进程实体的运行过程,是系统进行资源分配和调度的一个独立单位。

注:进程实体是静态的,进程是动态的

二、进程的组成

在这里插入图片描述
在这里插入图片描述

题目形式:给一个数据,判断是否保存在PCB中
不需要记忆所有PCB存放信息,只要是与进程管理相关的数据一定存放在PCB中
程序段是存放执行的代码
数据段存放运行过程中处理的各种数据

三、进程的组织

进程的组成是进程内部构成
进程的组织是多个进程间的组织方式
在这里插入图片描述

1、链接方式

在这里插入图片描述

2、索引方式

在这里插入图片描述

四、进程的特征

在这里插入图片描述

动态性、并发性、独立性、异步性、结构性

五、总结

在这里插入图片描述

进程的状态与转换

一、进程的状态

基本状态:
运行态:占有CPU,并在CPU运行。单核只能有一个进程处于运行态,双核可以有两个
就绪态:已具备运行条件,但没有空闲CPU,而暂时不能运行。已拥有除CPU以外的所有需要资源
阻塞态(等待态):因等待某一事件时不能运行。如等待操作系统分配打印机、读磁盘等操作,即运行时进程主动向系统获取资源请求或被中断

另外两种状态:
创建态(新建态):进程正在被创建,操作系统为进程分配资源,初始化PCB
撤销态(结束态):进程正在从系统中撤销,操作系统会回收进程拥有的资源、撤销PCB

在这里插入图片描述

二、总结

在这里插入图片描述

进程控制

进程控制:实现进程状态的转换
进程状态的转换需要在不同时期将PCB放入不同的队列,并且需要更改PCB中的数据,如果PCB的状态标志位与当前队列不同,则极有可能发生错误,这时我们可以使用原语实现进程控制。

一、原语

原语:用于保存进程的环境,防止进程破坏,执行期间不允许被中断
关中断指令
原语代码1
原语代码2
开中断
代码3
代码4

关/开中断指令的权限很大,值允许在核心态执行特权指令

原语做的事情

  1. 更新PCB中的信息
    a. 所有进程控制的原语一定修改进程状态标志位
    b. 剥夺CPU前,先保存期允许环境
    c. 某进程开始运行前必然要恢复期运行环境
  2. 将PCB插入适合的队列
  3. 分配/回收资源

相关原语:
创建、终止、阻塞、唤醒、切换进程

进程通信

进程通信:进程之间信息交换
进程的地址控制是独立的,进程之间不能直接访问,系统将提供访问方法

进程通信:共享存储、消息传递、管道通信

一、共享存储

共享空间的访问必须是互斥的(操作系统提供的互斥工具(P、V操作)

  1. 基于数据结构的共享:如共享空间只能放一个长度为10的数组。这种共享方式速度慢、限制多,低级共享
  2. 基于存储区的共享:在内存中画出一块共享存储区,数据的形式、存放位置都由进程控制,而不是操作系统。速度更快,高级共享
二、管道通信
  1. 管道通信只能采用半双工通信,某一时间段内只能实现单向传输。如果要实现双向同时通信,则需要设置两个管道
  2. 各进程要互斥访问管道
  3. 数据以字符流的形式写入管道,当管道写满,write()阻塞,等待读进程将数据取走,管道变空,此时读进程read()被阻塞
  4. 如果没写满,就不允许读。如果没读空,就不允许写
  5. 数据一旦被读出,就从管道中被抛弃,这就意味着读进程只能有一个,否则会读错数据,如本来进程2要读的数据被进程3读了导致错误
    在这里插入图片描述
三、消息传递

进程间的数据交换一格式化的消息为单位
操作系统提供“发送消息/接收消息”两个原语进程数据交换
在这里插入图片描述

四、总结

在这里插入图片描述

线程

线程:线程是一个基本的CPU执行单元,也是程序执行流的最小单位
进程可并发,线程也可并发,提升系统并发度
在这里插入图片描述

一、线程的实现方式

用户级线程:应用程序负责,用户态即可完成
内核级线程:由操作系统内核完成,必须在核心态完成

重点:内核级线程才是处理机分配的单位,如下图就算进程在4核处理机的计算机上运行,也最多只能被分配到两个核,最多两个用户线程并行执行
在这里插入图片描述

二、多线程模型

多对一模型:多个用户级线程映射到一个内核级线程
优点:用户级线程的切换在用户空间即可完成,不需要切换到核心态,线程管理的系统开销小,效率高
缺点:当一个用户级线程被阻塞后,整个进程都会被阻塞,并发度不高。多个线程不可在多核处理机上并行运行

一对一模型:一个用户级线程映射到一个内核级线程
优点:当一个线程被阻塞后,别的线程还可以继续执行,并发能力强。多线程可在多核处理机上并行执行。
缺点:一个用户进程会占用多个内核级线程,线程切换由操作系统内核完成,需要切换到核心态,因此线程管理的成本高,开销大。

多对多模型:m个用户级线程映射到n个内核级线程(m>=n)
克服了多对一模型并发度不高的缺点,又克服了一对一模型中一个用户进程占用太多内核级线程,开销太大的缺点。

三、总结

在这里插入图片描述

第二节

进程调度

调度:确定某种规则来决定处理这些任务的顺序
处理机调度:从就绪队列中按照一定的算法选择一个进程并将处理机分配给他运行,以实现进程的并发执行

高级调度(作业调度):按一定的原则从外存上处于后备队列的作业中挑选一个(或多个)作业,给他们分配内存等必要资源,并建立相应的进程(建立PCB),以使它(们)获得竞争处理机的权利。

中级调度(内存调度):就是要决定将哪个处于挂起状态的进程重新调入内存。
一个进程可能会被多次调出、调入内存,因此中级调度发生的频率要比高级调度更高。
在这里插入图片描述
低级调度(进程调度),其主要任务是按照某种方法和策略从就绪队列中选取一个进程,将处理机分配给它。
进程调度是操作系统中最基本的一种调度,在一般的操作系统中都必须配置进程调度。进程调度的频率很高,一般几十毫秒一次。

对比:
在这里插入图片描述

一、进程调度的时机

进程处于临界区时不能进行处理机调度(×)
进程在操作系统内核程序临界区中不能进行调度与切换(√)
内核程序需要上锁有序进行进行调度,外部设备如打印机处理慢,而CPU未执行任何操作,所以可以调度而不会影响打印机

临界资源:一个时间段内只允许一个进程使用的资源。各进程需要互斥地访问临界资源
临界区:访问临界自愿的那段代码
内核程序临界区:一般是用来访问某种内核数据结构的,比如进程的就绪队列

二、进程调度的方式
  1. 非剥夺调度方式,又称非抢占方式
  2. 剥夺调度方式,又称抢占方式
三、进程的切换与过程

进程的调度、切换是有代价的,并不是调度越频繁,并发度越高

调度算法

一、指标

CPU利用率:值CPU“忙碌”的时间栈总时间的比例
利用率=忙碌时间/总时间
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201123192601372.png#pic_cente

系统吞吐量:单位时间内完成作业的数量
系统吞吐量:总共完成了多少道作业/总共花了多少时间
在这里插入图片描述

  1. 周转时间:提交到完成的时间
    周转时间=作业完成时间-作业提交时间
  2. 平均周转时间=各作业周转时间之和/作业数
  3. 带权周转时间=作业周转时间/作业实际运行时间=(作业完成时间-作业提交时间)/作业实际运行时间
  4. 平均带权周转时间=个作业带权周转时间之和/作业数
  5. 等待时间:处于等待处理机状态时间之和
    等待时间=周转时间-运行时间-I/O操作时间
  6. 平均等待时间:即各个进程/作业等待时间的平均值
  7. 响应时间:用户提交请求到首次产生响应所用的时间
二、算法
  1. 先来先服务(FCFS)
  2. 短作业优先(SJF)
  3. 高响应优先算法(HRRN)
    注:饥饿:某进程、作业长期得不到服务
(一)FCFS

在这里插入图片描述

在这里插入图片描述

(二)SJF
  1. 非抢占式 短进程优先调度算法(SPF)
    在这里插入图片描述
    2.抢占式 最短剩余时间优先算法(SRTN)
    在这里插入图片描述

在这里插入图片描述

(三)HRRN

在这里插入图片描述

在这里插入图片描述

总结

在这里插入图片描述

(四)RR

在这里插入图片描述

在这里插入图片描述
补充:时间片要合理设置,太大会导致退化为先来先服务算法,会增大系统的响应时间,太小会导致进程切换过于频繁,导致系统会花大量的时间来处理进程切换,从而导致实际用于进程执行的时间比例减少

(五)优先级调度算法
  1. 非抢占式
    在这里插入图片描述
  2. 抢占式
    在这里插入图片描述
    在这里插入图片描述
(六)多级反馈队列调度算法

在这里插入图片描述
在这里插入图片描述

总结

在这里插入图片描述

第三节

进程同步、互斥

进程异步:并发执行的进程以各自独立的、不可预知的速度向前推进
进程同步:即直接制约关系,指为完成某种任务建立的一个或多个进程,所以需要在某些位置协调它们的工作次序而产生的制约关系
如:管道通信,必须先写数据到管道再读数据
进程互斥: 也称间接制约关系

  1. 互斥共享方式:一个时间段内置只允许一个进程访问该资源
  2. 同时共享方式:允许一个时间段内有多个进程“同时“”进行访问
    临界资源:一个时间段内只允许一个进程使用的资源。如物理设备(摄像头、打印机),许多变量、数据、内存缓冲区。

进程互斥访问四个部分:

do{
	entry section;//进入区(相当于上锁)
	critical section;//临界区(临界段:访问临界资源)
	exit section;//退出区(解锁)
	remainder section;//剩余区(其他处理)
}while(true)

为实现互斥访问需遵循的原则:

  1. 空闲让进。临界区空闲时允许一个请求进入空闲区的进程立即进入临界区
  2. 忙则等待。当已有进程进入临界区,其他进入临界区的进程必须等待
  3. 有限等待。对请求访问的进程,应保证在有限时间内进入临界区(不会饥饿)
  4. 让权等待。当进程不能进入临界区时,应立即释放处理机,防止进程忙等待。(注:忙等待,即等待时占用处理机,使处理机处于忙碌的状态)

进程互斥的软件实现方法

1.单标志法

算法思想:两个进程在访问完临界区后会把使用临界区的权限转交给另一个进程。每个进程进入临界区的权限只能被另一个进程赋予

int turn = 0; //turn 表示当前允许进入临界区的进程号
P0 进程:
while(turn != 0);//进入区
critical section;//临界区
turn = 1;//退出区
remainder section;//剩余区

P1 进程:
while(turn != 1);
critical section;
turn = 0;
remainder section;

主要问题:违背"空闲让进"原则,必须访问P0才能访问P1

2.双标志先检查

算法思想:设置一个布尔型数组flag[],数组中各个元素用来标记各进程想进入临界区的意愿

bool flag[2]; //表示进入临界区意愿的数组
flag[0] = false;
flag[1] = false; //刚开始设置为两个进程都不想进入临界区

P0进程:
while(flag[1]);//1.如果此时P0想进入临界区,P1就一直循环等待
flag[0] = true;//2.标记为P1进程想要进入临界区
critical section;//3.访问临界区
flag[0] = false;//4.访问完临界区,修改标记P1不想使用临界区
remainder section

P1进程:
while(flag[0]);//5
falg[1] = true;//6
critical section;//7
flag[1] = false;//8
remainder section;

主要问题:双标志先检查法的主要问题:违反"忙则等待"原则。进程存在异步性,如若按照152637…,的顺序执行,P0和P1将会同时访问临界区

3.双标志后检查

算法思想:先上锁后检查

bool flag[2]; //表示进入临界区意愿的数组
flag[0] = false;
flag[1] = false; //刚开始设置为两个进程都不想进入临界区

P0进程:
flag[0] = true;//1.标记为P1进程想要进入临界区
while(flag[1]);//2.如果此时P0想进入临界区,P1就一直循环等待 
critical section;//3.访问临界区
flag[0] = false;//4.访问完临界区,修改标记P1不想使用临界区
remainder section

P1进程:
falg[1] = true;//5
while(flag[0]);//6
critical section;//7
flag[1] = false;//8
remainder section;

主要问题: 若按照1526…的顺序执行,P0和P1将都无法进入临界前区
违背了"空闲让进"和"有限等待"原则,产生饥饿

4.Peterson算法
bool flag[2]; //表示进入临界区意愿的数组
flag[0] = false;
flag[1] = false; //刚开始设置为两个进程都不想进入临界区
int turn = 0;//turn 表示优先让哪个进程进入临界区

P0进程:
flag[0] = true;//1.标记为P1进程想要进入临界区
turn = 1;//2.谦让给P1
while(flag[1]&&turn == 1);//3.如果此时P0想进入临界区,P1就一直循环等待 
critical section;//4.访问临界区
flag[0] = false;//5.访问完临界区,修改标记P1不想使用临界区
remainder section

P1进程:
falg[1] = true;//6
turn  = 0;//7
while(flag[0]&&turn==0);//8
critical section;//9
flag[1] = false;//10
remainder section;

主要问题: 未遵循让权等待原则,while循环一直占用CPU

进程互斥硬件实现方法

1.中断屏蔽方法

利用"开/关中断指令"
优点:简单、高效
缺点:不适用多处理机;只适用于操作系统内核进程,不适用于用户进程,如果用户随意使用会很危险

2.TestAndSet指令

简称TS指令,也称TestAndSetLock指令或TSL指令
TSL指令是用硬件实现的,执行的过程不允许被中断,只能一气呵成

//true表示已加锁,false表示未加锁
bool TestAndSet(bool *lock){
	bool old;
	old = *lock;//old用来存放lock原来的值
	*lock = true;//无论之前是否已加锁,都将lock设置为true
	return old;//返回lock原来值
}

//TSL互斥逻辑
whlie(TestAndSet(&lock));//"上锁"并"检查"
临界区代码段
lock = false;//解锁
剩余区代码...

优点:实现简单,适用于多处理机
缺点:不满足“让权等待”原则,暂时无法进入临界区的进程会占用CPU并循环执行TSL指令,从而导致“忙等”。

3.Swap指令

也叫Exchange指令,或简称XCHG指令。
Swap指令是用硬件实现的,执行过程不允许被中断,只能一气呵成

Swap(bool *a, bool *b){
	bool temp;
	temp = *a;
	*a = *b;
	*b = temp;
}

//算法逻辑
bool old = true;
while(old == true)
	Swap(&lock, &old);
临界区代码段
lock = false;//解锁
剩余区代码...

逻辑上与TSL并无太大差别

信号量机制

四种软件实现方式,三种硬件实现方式存在的问题
1.双标法“检测”、“上锁”无法一气呵成
2.所有方案无法实现“让权等待”

信号量机制:用户进程可以使用操作系统提供的一对原语来对信号量进行操作,从而很方便的实现了进程互斥、进程同步

信号量是一个变量,可以用一个信号量表示系统中某种资源的数量
原语是一种特殊的程序段。其执行只能一气呵成,不可被中断

一对原语:wait(S)原语和signal(S)原语,可以把原语理解为我们自己写的函数.括号S为传入的参数
wait、signal原语简称P、V操作,所以可以简写成P(S)、V(S)

1、整形信号量
int S = 1;//初始化整型信号量s,表示当前系统中可用的打印机资源
void wait (int S) { // wait原语,相当于”进入区”
	while (S<=0);//如果资源数不够,就一直循环等待
	S=S-1;//如果资源数够,则占用一个资源
}
void signal (int S) { // signal原语,相当于“退出区”
	S=S+1;//使用完资源后,在退出区释放资源
}

进程P0
...
wait(S);//进入区,申请资源
使用打印机资源...//临界区,访问资源
signal(S);//退出区,释放资源
...

进程P1
...
wait(S);
使用打印机资源...
signal(S);
...

进程n
...

缺点:不能“让权等待”,“忙等”

2、记录型信号量
/*记录型信号量的定义*/
typedef struct {
	int value;//剩余资源数
	Struct process *L;//等待队列
}semaphore;
/*某进程需要使用资源时,通过wait原语申请*/
void wait (semaphore S) {
	S.value--;
	if (S.value < 0 ) {
		block (S.L);
	}
}
/*进程使用完资源后,通过signal原语释放*/
void signal (semaphore S) {
	S.value++;
	if ( s.value <= 0) {
		wakeup(S.L);
	}
}

实现了:让权等待、空闲让进、有限等待、忙则等待

信号量实现进程互斥、同步、前驱关系

一、信号量机制实现进程互斥
/*信号量机制实现互斥*/
semaphore mutex=1;//初始化信号量
P1(){
	P(mutex);//使用临界资源前需要加锁
	临界区代码段...
	V(mutex);//使用临界资源后需要解锁
}

P2(){
	P(mutex);
	临界区代码段...
	v(mutex) ;
}
二、信号量机制实现进程同步

为了使代码1、2,在代码3、4、5前执行
在代码1、2后执行一个V操作,即解锁唤醒操作,在P2()开始执行一个P操作,即上锁阻塞操作。
如果先执行了V(S)
由于V(S)释放了资源S,S++,P(S)不会执行block原语,继续执行代码4
如果先执行了P(S)
由于S=0,S–,S=-1<0因此P操作会执行block原语阻塞P2运行

/*信号量机制实现同步*/
semaphore S=0;//初始化同步信号量,初始值为0

P1(){
	代码1;
	代码2;
	V(S);
	代码3;
}

P2(){
	P(S);
	代码4;
	代码5;
	代码6;
}
三、信号量机制实现前驱关系

在这里插入图片描述

生产者-消费者问题

系统中有一组生产者进程和一组消费者进程,生产者进程每次生产一个产品放入缓冲区,消费者进程每次从缓冲区去除一个产品并使用。
生产者和消费者共享一个初始为空、大小为n的缓冲区
只有缓冲区没满时,生产者才能把产品放入缓冲区,否则必须等待。
缓冲区是临界资源,各进程必须互斥访问

使用信号量机制(P、V操作)实现生产者、消费者进程的这些功能
信号量机制可实现互斥、同步、对一类资源的申请和释放

PV操作题目分析步骤
PV操作题目的解题思路:
1.关系分析。找出题目中描述的各个进程,分析它们之间的同步、互斥关系。
2.整理思路。根据各进程的操作流程确定P、V操作的大致顺序。
3.设置信号量。设置需要的信号量,并根据题目条件确定信号量初值。(互斥信号量初值一般为1,同步信号量的初始值要看对应资源的初始值是多少)

semaphore mutex = 1;//互斥信号量,实现对缓冲区的互斥访问
semaphore empty = n;//同步信号量,表示空闲缓冲区的数量
semaphore full = 0;//同步信号量,表示产品的数量,即非空缓冲区的数量

producer(){
	while(1){
		生产一个产品;
		P(empty);
		P(mutex);
		吧产品放入缓冲区;
		V(mutex);
	}

}

consumer(){
	while(1){
		P(full);
		P(mutex);
		从缓冲区取出一个产品
		V(mutex);
		V(empty);
		使用产品;
	}
}

顺序分析:P操作不能随意交换,会导致死锁,V操作可交换

多生产者多消费者问题

例题:桌子上有一只盘子,每次只能向其中放入一个水果。爸爸专向盘子中放苹果,妈妈专向盘子中放橘子,儿子专等着吃盘子中的橘子,女儿专等着吃盘子中的苹果。只有盘子空时,爸爸或妈妈才可向盘子中放一个水果。仅当盘子中有自己需要的水果时,儿子或女儿可以从盘子中取出水果。用PV操作实现上述过程。

在这里插入图片描述
在这里插入图片描述
总结:在生产者-消费者问题中,如果缓冲区大小为1,那么有可能不需要设置互斥信号量就可以实现互斥访问缓冲区的功能。当然,这不是绝对的,要具体问题具体分析。
建议:在考试中如果来不及仔细分析,可以加上互斥信号量,保证各进程一定会互斥地访问缓冲区。但需要注意的是,实现互斥的P操作一定要在实现同步的P操作之后,否则可能引起“死锁”。
PV操作题目的解题思路:

  1. 关系分析。找出题目中描述的各个进程,分析它们之间的同步、互斥关系。
  2. 整理思路。根据各进程的操作流程确定P、V操作的大致顺序。
  3. 设置信号量。设置需要的信号量,并根据题目条件确定信号量初值。(互斥信号量初值一般为1,同步信号量的初始值要看对应资源的初始值是多少)

抽烟者问题

假设一个系统有三个抽烟者进程和一个供应者进程。每个抽烟者不停地卷烟并抽掉它,但是要卷起并抽掉一支烟,抽烟者需要有三种材料:烟草、纸和胶水。三个抽烟者中,第一个拥有烟草、第二个拥有纸、第三个拥有胶水。供应者进程无限地提供三种材料,供应者每次将两种材料放桌子上,拥有剩下那种材料的抽烟者卷一根烟并抽掉它,并给供应者进程一个信号告诉完成了,供应者就会放另外两种材料再桌上,这个过程一直重复(让三个抽烟者轮流地抽烟)
在这里插入图片描述
在这里插入图片描述

读者-写者问题

有读者和写者两组并发进程,共享一个文件,当两个或两个以上的读进程同时访问共享数据时不会产生副作用,但若某个写进程和其他进程(读进程或写进程)同时访问共享数据时则可能导致数据不一致的错误。因此要求:①允许多个读者可以同时对文件执行读操作;②只允许一个写者往文件中写信息;③任一写者在完成写操作之前不允许其他读者或写者工作;④写者执行写操作前,应让已有的读者和写者全部退出。
在这里插入图片描述
在这里插入图片描述

哲学家进餐问题

一张圆桌上坐着5名哲学家,每两个哲学家之间的桌上摆一根筷子,桌子的中间是一碗米饭。哲学家们倾注毕生的精力用于思考和进餐,哲学家在思考时,并不影响他人。只有当哲学家饥饿时,才试图拿起左、右两根筷子(一根一根地拿起)。如果筷子已在他人手上,则需等待。饥饿的哲学家只有同时拿起两根筷子才可以开始进餐,当进餐完毕后,放下筷子继续思考。
①可以对哲学家进程施加一些限制条件,比如最多允许四个哲学家同时进餐。这样可以保证至少有一个哲学家是可以拿到左右两只筷子的
②要求奇数号哲学家先拿左边的筷子,然后再拿右边的筷子,而偶数号哲学家刚好相反。用这种方法可以保证如果相邻的两个奇偶号哲学家都想吃饭,那么只会有其中一个可以拿起第一只筷子,另一个会直接阻塞。这就
避免了占有一支后再等待另一只的情况。
③仅当一个哲学家左右两支筷子都可用时才允许他抓起筷子。

semaphore chopstick [ 5]-{1,1,1,1,1};
semaphore mutex = 1;//互斥地取筷子
Pi(){//i号哲学家的进程
while(){
	P(chopstick[i]);//拿左
	P(chopstick [ (i+1)%5]);//拿右
	吃饭...
	v(chopstick [i]);//放左
	v(chopstick[ (i+1)%5]);//放右
	思考..
	}
)

管程

解决编写程序困难、易出错问题

管程是一种特殊的软件模块,有这些部分组成:

  1. 局部于管程的共享数据结构说明;
  2. 对该数据结构进行操作的一组过程;
  3. 对局部于管程的共享数据设置初始值的语句;
  4. 管程有一个名字。
    类似于类

管程的基本特征:

  1. 管程中定义的数据只能被管程的函数修改
  2. 管程中同一时刻只允许一个进程执行某个函数

第四节

死锁

死锁:在并发环境下,各进程因竞争资源而造成的一种互相等待对方手里的资源,导致各进程都阻塞,都无法向前推进的现象
在这里插入图片描述

一、死锁产生必要条件
  1. 互斥条件:只有对必须互斥使用的资源的争抢才会导致死锁(如哲学家的筷子、打印机设备)。像内存、扬声器这样可以同时让多个进程使用的资源是不会导致死锁的(因为进程不用阻塞等待这种资源)。
  2. 不剥夺条件:进程所获得的资源在未使用完之前,不能由其他进程强行夺走,只能主动释放。
  3. 请求和保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源又被其他进程占有,此时请求进程被阻塞,但又对自己已有的资源保持不放。
  4. 循环等待条件:存在一种进程资源的循环等待链,链中的每一个进程己获得的资源同时被下一个进程所请求。
    注意!发生死锁时一定有循环等待,但是发生循环等待时未必死锁(循环等待是死锁的必要不充分条件)
二、发生死锁时间

对不可剥夺资源的不合理分配,可能导致死锁

三、死锁处理策略
  1. 预防死锁。破坏死锁产生的四个必要条件中的一个或几个。
  2. 避免死锁。用某种方法防止系统进入不安全状态,从而避免死锁(银行家算法)
  3. 死锁的检测和解除。允许死锁的发生,不过操作系统会负责检测出死锁的发生,然后采取某种措
    施解除死锁。

死锁的解决方法

一、破坏互斥条件

互斥条件:只有对必须互斥使用的资源的争抢才能导致死锁
如果只能互斥使用的资源改造为允许共享使用,比如SPOOLing技术,
缺点:并不是所用的资源都可以改造成共享使用的资源,很多地方必须保护互斥性

二、破坏不剥夺条件

不剥夺条件:进程所获得的资源在未使用完之前,不能由其他进程强行夺走,只能主动释放

破坏不剥夺条件:
方案一:当某个进程请求新的资源得不到满足时,他必须立即释放保持的所有资源,待以后需要时重新申请
方案二:当某个进程需要的资源被其他进程所占有时,可由操作系统协助,将想要的资源强行剥夺。(需要考虑进程优先级)
缺点:

  1. 实现起来复杂
  2. 已获得的资源可能造成前一阶段工作的失效。因此这种方法一般只适用于保存和恢复资源,如CPU
  3. 反复的申请和释放资源会增加系统开销,降低系统吞吐量
  4. 若采用方案一,意味着只要暂时得不到某个资源,之前获得的那些资源就都需要放弃,以后再重新申请。如果一直发生这样的情况,就会导致进程饥饿
三、破坏请求和保持条件

请求和保持条件:进程已经保持至少一个资源,但又提出了新的资源请求,而该资源又被其他进程占有,此时请求进程被阻塞,但又对自己已有的资源保持不放。

可以采用静态分配方法,即进程在运行前一次申请完它所需的全部资源,在他的资源未满足前,不让他投入运行。一旦投入运行后,这些资源就一直归他所有,该进程不会请求别的任何资源

缺点:有些资源可能只需要用很短的时间,因此如果进程的整个运行期间都一直保持着所有资金,就会造成严重的资源浪费,资源利用率低,该策略也可能导致某些资源饥饿

四、循环等待条件

循环等待条件:存在一种进程资源的循环等待链,链中的每一个进程已获得的资源同时被下一个进程所请求。

可采用顺序资源分配法。首先给系统中的资源编号,规定每个进程必须按编号递增的顺序请求资源,同类资源一次申请完。

原理分析:一个进程只有已占有小编号资源时,才有资格申请更大编号的资源。

缺点:

  1. 不方便增加新设备,可能需要重新改设备编号
  2. 进程实际使用资源顺序可能和编号顺序不一致,会导致资源浪费
  3. 必须按照规定次序申请资源,用户编程麻烦。

分析哲学家进餐问题三种解决方案是破坏死锁的什么条件

安全序列

安全序列:如果系统按照这种序列分配资源,则每个进程都能顺利完成。只要找到一个安全序列,系统就是安全状态。安全序列可以有多个。
不安全状态:找不到一个安全序列
安全状态:如果系统进入安全状态一定不会发生死锁,进入不安全状态可能会发生死锁,死锁一定进入了不安全状态

银行家算法

提出人:荷兰学者Djikstra(PV操作提出者)
核心思想:在进程提出资源申请时,先预判此次分配是否会导致系统进入不安全状态,就暂时不答应此次请求,让该进程先阻塞等待

数据结构:
长度为m的一维数组Available表示还有多少可用资源
nm矩阵Max表示各进程对资源的最大需求数
n
m矩阵Allocation表示已经给各进程分配了多少资源
Max - Allocation = Need矩阵表示各进程最多还需要多少资源用长度为m的一位数组Request表示进程此次申请的各种资源数

银行家算法步骤:
①检查此次申请是否超过了之前声明的最大需求数
②检查此时系统剩余的可用资源是否还能满足这次请求③试探着分配,更改各数据结构
④用安全性算法检查此次分配是否会导致系统进入不安全状态

安全性算法步骤:
检查当前的剩余可用资源是否能满足某个进程的最大需求,如果可以,就把该进程加入安全序列,并把该进程持有的资源全部回收。
不断重复上述过程,看最终是否能让所有进程都加入安全序列。

死锁的处理策略

在这里插入图片描述

一、死锁的检测

如何检测是否死锁

  1. 用某种数据结构来保存资源的请求和分配信息
  2. 提供一种算法,利用上述信息来检测系统是否已进入死锁状态。
    在这里插入图片描述
    检测方法:形同银行家算法分析安全按序列思路,如果能消除所有边,就成这个图是可以完全简化的。此时一定没有发生死锁,如果不能消除所有边,那么此时就是发生了死锁

算法思路:在资源分配图中,找出既不阻塞又不是孤点的进程Pi(不阻塞:即请求的资源小于空闲资源,不是孤点:即有边存在),消去它所有的请求边和分配边,使其变成孤点,最终使所有点变成孤点,则无死锁。

二、死锁的解除
  1. 资源剥夺法:挂起(暂放外存)某些死锁进程,并抢占它的资源,将这些资源分配给其他的死锁进程。但要防止死锁进程饥饿
  2. 撤销进程法(终止进程法)。强制撤销部分、甚至全部死锁进程,并剥夺这些进程的资源。优点:实现简单,但代价大,因为有些进程可能运行很长时间快结束了,一旦终止功亏一篑
  3. 进程回退法。让一个或多个死锁进程回退到足以避免死锁的地步。系统需要记录进程的历史信息,设置还原点。

如何决定对哪个进程操作

  1. 进程优先级(进程优先级低的下手)
  2. 已执行多长时间(进程时间短的牺牲)
  3. 还要多久完成(让快完成的进程获得资源)
  4. 进程已经使用了多少资源(让占用资源多的进程牺牲)
  5. 进程是交互式的还是批处理方式(交互式:与用户交互,批处理式:计算用户对于这种进程的及时反馈)

总结

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Baal Austin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值