操作系统---处理机调度和死锁

目录

处理机调度

作业和作业调度

作业

作业控制块

作业调度的主要任务

处理机调度的层次

1、高级调度(作业调度)(作业进入内存,创建态-》就绪态)

2、中级调度(内存调度)(进程在内外存切换)

3、低级调度(进程调度)(就绪态-》运行态)

进程调度

进程调度任务

进程调度方式

进程调度时机

调度算法的评价标准

先来先服务调度算法(First comes first server ,FCFS)

短进程优先调度算法(shorted job first,SJF)

非抢占式(SJF)

 抢占式(最短剩余时间优先算法:SRTN)

高响应比优先算法

时间片轮转算法(RR)

优先级调度算法

多级反馈队列调度算法

进程调度算法总结

死锁

 死锁的概念

 死锁同时满足的四个条件

预防死锁-》保证不发生死锁

避免死锁

银行家算法

 1、银行家算法中的数据结构 

2、银行家算法

 3、安全性算法

银行家算法的实现

死锁检测和解除

死锁检测

 死锁解除


处理机调度

调度:对资源的分配;例如有8个糖果,如何分给3个人?

处理机调度:在多道程序系统中,进程数目一般是很多的,处理机数目就那么多,如何将处理机合理并正确的分给进程,这就是处理机调度的工作内容

进程此时还没有获取cpu:就绪态

作业和作业调度

作业是用户提交给系统的一项相对独立的工作

在多道批处理系统(一种操作系统模式)中,用户通过输入设备提交作业,提交的作业被先存放在外存(磁盘)中排成一个队列,称之为”后备队列"。作业调度会将作业从外存调入内存

作业

一个广泛的概念,包括通常的程序和数据,而且配有一个“说明书”,系统根据说明书”对程序的运行进行控制。多道批处理系统中,作业会作为基本的单位从外存调入内存

作业控制块

为了管理和调度作业,多道批处理系统中为每一个作业都设置一个作业控制块(JCB),是作业在系统存在的标志,包含了系统对作业管理和调度的全部信息

创建作业时,为其分配JCB,加载进入作业后备队列,等待调度后加入内存,作业运行结束,系统撤回资源并回收PCB

作业调度的主要任务

根据JCB信息来合理调度作业进入内存

处理机调度的层次

1、高级调度(作业调度)(作业进入内存,创建态-》就绪态)

调度对象:作业

调度目的:后备队列中的作业要调入内存,但是内存空间是有限的,要选择性的调入某一部分作业。高级调度就是根据某一种算法,决定将处于后备队列的哪几个作业调入内存,为其分配资源,并分配PCB(让其称为进程)将其加入到就绪队列当中

高级调度主要用于多道批处理系统

作业-》进程

2、中级调度(内存调度)(进程在内外存切换)

目的:提高内存利用率和系统吞吐量

将暂时不运行的进程调至外存等待(挂起状态),当他们具备运行条件或者内存空闲时,中级调度会决定将外存中具备运行条件的挂起状态进程加载进入内存,并修改状态为就绪态,等待进程调度

挂起状态:暂时存放进入外存

在将暂时不运行的进程调至外存等待的过程中,PCB不会一起被调入外存,PCB常驻内存,PCB会记录进程挂起的位置,进程状态等信息,便于操作系统的进程管理。被挂起来的进程(包括PCB)会加载进入挂起队列

3、低级调度(进程调度)(就绪态-》运行态)

调度对象:进程

调度功能:根据某种算法,决定让哪一个处于就绪队列的进程获得处理机,并由分派程序将处理机分派给进程

低级调度是最基本的调度,在多道批,分时(一台计算机同时服务于多个用户),实时(任务在一定时间内完成)三个系统中都应该存在

进程从就绪态-》运行态

进程调度

进程调度,也就是低级调度,按照某一种算法选择就绪队列的进程,给进程分配CPU,让其进入运行态

进程调度任务

1、保护CPU现场:在进程调度时,要保护好当前CPU的信息

2、按照某一种算法选取进程:进程调度需要从就绪队列中选择一个进程,修改状态为运行态,准备分配CPU

3、分配CPU:分配程序将CPU分派给进程:将选中进程的PCB内的有关进程调度之前CPU的信息同步给CPU(让CPU得到进程上次结束的信息,可以接着上次的断点执行),将CPU分配给进程

进程调度方式

分为抢占式和非抢占式

非抢占式:一旦某一个进程获取到了CPU,进入运行态,CPU不会被其他进程所占领,除非这个进程因为正常运行结束或者自动地因为等待某种事件的完成,从而主动放弃CPU,这时其他进程可以得到CPU

抢占式:根据某一种算法或者原则,可以去终止某一个正在运行的程序,将这个进程的CPU分配给另外一个进程,抢占CPU

主要原则:

1、优先级优先原则:允许优先级更高的进程抢占处理机

2、短进程优先原则:允许新来的短进程抢占当前长进程的处理机(长短进程:运行时间)

3、时间片原则:各个进程按照时间片轮转运行时,正在执行的进程将一个时间片用完之后,便立刻停止该进程的执行而重新调度

进程调度时机

 不能进行进程调度的时机

调度算法的评价标准

1、cpu利用率:

 

2、系统吞吐量:单位时间内完成作业的数量

3、周转时间 :作业运行的时间(作业提交给系统到作业运行结束)

分为四部分:1、作业提交给系统(作业载入外存)后,作业在外存等待被作业调度(加载进入内存的就绪队列)的时间2、进程加载进入就绪队列后等待进程调度(分配CPU)的时间3、进程在运行态的时间4、如果发生系统调用等,进程进入阻塞态,等待I/O操作完成的时间

周转时间:作业运行结束-作业提交给系统的时间

1、周转时间(作业周转时间): 作业运行结束的时间-作业到达的时间

2、等待时间:周转时间-运行时间-I/O操作时间

3、平均周转时间:所有作业的周转时间之和/作业数

4、带权周转时间:周转时间/运行时间

先来先服务调度算法(First comes first server ,FCFS)

算法思想:按照进程到达的时间来选择进程

调度方式:非抢占式

 分析:

 算法优缺点:对长进程友好,短进程不友好

不会导致饥饿(饥饿:某一进程长期得不到cpu)

进程根据等待时间轮流执行,不会导致饥饿

短进程优先调度算法(shorted job first,SJF)

算法思想:按照作业所要求的运行时间来衡量进程长短,进程短的优先

选择当前已经到达并且运行时间短的进程

调度方式:非抢占式和抢占式

非抢占式(SJF)

 抢占式(最短剩余时间优先算法:SRTN)

算法优缺点:对短进程友好,对长进程不友好

可能导致长进程饥饿(短进程优先,短进程很多的情况下导致饥饿)

高响应比优先算法

算法思想:同时考虑等待时间和运行时间

计算响应比,选取响应比高的进程执行

响应比=(等待时间+运行时间)/运行时间=(周转时间)/运行时间 

 调度方式:非抢占式

 算法优缺点:同时考虑等待时间和运行时间,综合了前面两个算法的优点

不会造成饥饿

批处理系统中处理机调度的目标就是平均周转时间,CPU利用率,公平性等

分时操作系统注重于响应时间

响应时间:分时系统选择进程的重要原则,响应时间指从用户通过键盘提交一个请求开始,到屏幕显示出结果的时间,包括三部分:1、请求信息从键盘输入开始直到传送到处理机的时间2、处理机对请求信息进行处理的时间3、形成的响应信息输出到显示器的时间

时间片轮转算法(RR)

算法思想:各个进程轮流执行一个时间片,一个进程的时间片用完被别的进程抢占CPU

一个进程的时间片用完后加入就绪队列队尾,每次选取就绪队列的队头进程执行(先到先得)

注意:进程运行结束但是时间片没用完,进程这时主动放弃处理机,继续开始调度

 调度方式:抢占式

时间片是2

时间片是5

 如果时间片过大,致使每一个进程在一个时间片内都可以完成,那么和先来先服务算法相对比没有区别,时间片轮转算法就会退化为先来先服务算法。

如果时间片太小,进程就需要频繁的加入和离开就绪队列,而这样的进程切换是需要很大的开销的

优点:响应快速

缺点:涉及到进程切换的开销,需要选择合适的时间片

不会导致饥饿

优先级调度算法

算法思想:每个进程都有优先级,选择优先级高的进程执行

实现方式:抢占式和非抢占式

 非抢占式:(例题设置:优先数高,优先级高)

 抢占式:

多级反馈队列调度算法

算法思想:

1、设置多级队列,队列的优先级不一样,所占时间片也不同(时间片调度)

2、一个进程刚刚到达,直接进入第一级队列(优先级最高),抢占CPU运行

3、一个进程时间片用完了,但是没运行结束,进入下一级队列的队尾(先来的进程先调用)

4、一个进程时间片没用完,被刚到来的进程抢占了CPU,那么这个进程仍然在这级队列中,不会进入下一级队列

5、只有前面的队列全空了,才可以为后面的进程分配资源(优先级调度)

 调度方式:抢占式算法

进程调度算法总结

死锁

 死锁的概念

各个进程在互相等待对方进程已经占据有的资源,导致各个进程都陷入阻塞,无法向前推进

饥饿:某一个进程长时间得不到所需资源,而长时间等待的现象

死循环:进程因为某种原因,陷入某个循环无法走出

 死锁同时满足的四个条件

进程A拥有打印机这个资源,进程B拥有雕刻机这个资源,A申请雕刻机,B申请打印机,而AB陷入阻塞,产生死锁

1、互斥条件:一个资源同一时间内只可以被一个进程使用

打印机这个进程在同一时间只能被一个进程使用

2、请求和保持条件:一个进程至少占有一个资源,但是又申请其他资源,但是申请的资源被其他进程占有,此时进程陷入阻塞,同时自己拥有的资源不会被释放

进程A拥有打印机这个资源,进程B拥有雕刻机这个资源,A申请雕刻机陷入阻塞,但是打印机这个资源仍被A占有,否则B进程就可以获取到打印机,就不会产生死锁

3、不可抢占条件:一个进程的资源不可以被其他进程抢占

A进程使用打印机,B进程申请使用打印机就必须在A进程放弃打印机之后才可以使用,不可以抢占打印机资源

4、循环等待条件:A进程占有B进程申请的资源,B进程占有A进程申请的资源,存在着“进程-资源"循环链

预防死锁-》保证不发生死锁

预防死锁:破坏四个条件的任意一个条件

四个条件任意一个条件不满足,死锁都不能产生

避免死锁

在资源的动态分配过程中,用某种方法防止系统陷入不安全状态,从而避免死锁

在避免死锁方法中,系统状态分为两个状态:安全状态时可避免产生死锁,不安全状态可能产生死锁

银行家算法

在资源分配之前,检测资源分配之后是否会产生不安全现象

 1、银行家算法中的数据结构 

1)可利用资源向量Available

是个含有m个元素的数组,其中的每一个元素代表一类可利用的资源数目。如果Available[j]=K,则表示系统中现有Rj类资源K个。 

2)最大需求矩阵Max

这是一个n×m的矩阵,它定义了系统中n个进程中的每一个进程对m类资源的最大需求。如果Max[i,j]=K,则表示进程i需要Rj类资源的最大数目为K。

3)分配矩阵Allocation

这也是一个n×m的矩阵,它定义了系统中每一类资源当前已分配给每一进程的资源数。如果Allocation[i,j]=K,则表示进程i当前已分得Rj类资源的数目为K。

4)需求矩阵Need。

这也是一个n×m的矩阵,用以表示每一个进程尚需的各类资源数。如果Need[i,j]=K,则表示进程i还需要Rj类资源K个,方能完成其任务。  

Need[i,j]=Max[i,j]-Allocation[i,j] 

2、银行家算法

设Requesti是进程Pi的请求向量,如果Requesti[j]=K,表示进程Pi需要K个Rj类型的资源。当Pi发出资源请求后,系统按下述步骤进行检查:

(1)如果Requesti[j]≤Need[i,j],便转向步骤(2);否则认为出错,因为它所需要的资源数已超过它所宣布最大值。

(2)如果Requesti[j]≤Available[j],便转向步骤(3);否则,表示尚无足够资源,Pi须等待。 

(3)系统试探着把资源分配给进程Pi,并修改下面数据结构中的数值:

Available[j]=Available[j]-Requesti[j];

Allocation[i,j]=Allocation[i,j]+Requesti[j];  

Need[i,j]=Need[i,j]-Requesti[j];

系统执行安全性算法,检查此次资源分配后,系统是否处于安全状态。若安全,才正式将资源分配给进程Pi,以完成本次分配;否则,将本次的试探分配作废,恢复原来的资源分配状态,让进程Pi等待。

 3、安全性算法

1)设置两个向量:

工作向量Work: 它表示系统可提供给进程继续运行所需的各类资源数目,它含有m个元素,在执行安全算法开始时,Work=Available;

工作向量Finish: 它表示系统是否有足够的资源分配给进程,使之运行完成。开始时先做Finish[i]=false; 当有足够资源分配给进程时, 再令Finish[i]=true。 

2)从进程集合中找到一个能满足下述条件的进程:         

Finish[i]=false;

Need[i,j]≤Work[j];若找到,执行 (3),否则,执行 (4)

3)当进程Pi获得资源后,可顺利执行,直至完成,并释放出分配给它的资源,故应执行:

Work[j]=Work[i]+Allocation[i,j];

Finish[i]=true;

go to step 2);

4)如果所有进程的Finish[i]=true都满足, 则表示系统处于安全状态;否则,系统处于不安全状态

银行家算法的实现

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#define MAXN 10//定义最大的进程数
#define MAXM 10//定义最大的资源种类总数


void init(int n, int m, char name[][2], int max[MAXN][MAXM], int Allocation[][MAXM]) {
	for (int i = 0; i < n; i++) {
		char ch='0';
		while (ch != '\n')
			ch=getchar();

		printf("输入进程名(两位),进程的最大需求,进程已经分配的资源\n");
		for (int j = 0; j < 2; j++)
			scanf("%c", &name[i][j]);
		for (int j = 0; j < m; j++) {
			scanf("%d", &max[i][j]);
		}
		for (int j = 0; j < m; j++) {
			scanf("%d", &Allocation[i][j]);
			if (Allocation[i][j] > max[i][j]) {
				printf("资源已经分配的资源大于了最大需求,请重新输入\n");
				Allocation[i][j] = 0;
				i--;
				break;
			}
		}
	}
}
void print(int n, int m, char name[][2], int max[MAXN][MAXM], int Allocation[][MAXM], int need[][MAXM]) {
	for (int i = 0; i < n; i++) {

		printf("进程名: ");
		printf("%c%c ", name[i][0], name[i][1]);
		printf("进程的最大需求: ");
		for (int j = 0; j < m; j++) {
			printf("%d ", max[i][j]);
		}
		printf("进程已经分配的资源: ");
		for (int j = 0; j < m; j++) {
			printf("%d ", Allocation[i][j]);
		}
		printf("进程已经最多还需要的资源: ");
		for (int j = 0; j < m; j++) {
			printf("%d ", need[i][j]);
		}
		printf("\n");
	}
}
void initNeed(int n, int m, int max[MAXN][MAXM], int Allocation[][MAXM], int need[][MAXM]) {
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			need[i][j] = max[i][j] - Allocation[i][j];
		}
	}
}
void initAvailable(int n, int m, int Available[MAXM],int Allocation[MAXN][MAXM]) {
	printf("输入每一种资源类型的数目\n");
	for (int i = 0; i < m; i++)
		scanf("%d", &Available[i]);
	for (int i = 0; i < m; i++) {
		for (int j = 0; j < n; j++) {
			Available[i] -= Allocation[j][i];
		}
	}
}
void printAvailable(int n, int m, int Available[MAXM]) {
	printf("系统内可用资源数\n");
	for (int j = 0; j < m; j++) {
		printf("%d ", Available[j]);
	}
	printf("\n");
}
/*工作向量Work: 它表示系统可提供给进程继续运行所需的各类资源数目,它含有m个元素,在执行安全算法开始时,Work=Available; 
* 工作向量Finish: 它表示系统是否有足够的资源分配给进程,使之运行完成。开始时先做Finish[i]=false;
当有足够资源分配给进程时, 再令Finish[i]=true。 
2)从进程集合中找到一个能满足下述条件的进程:         
Finish[i]=false; 
Need[i,j]≤Work[j];
若找到,执行 (3),否则,执行 (4)
3)当进程Pi获得资源后,可顺利执行,直至完成,并释放出分配给它的资源,故应执行:
Work[j]=Work[i]+Allocation[i,j];
Finish[i]=true;
go to step 2; 
4)如果所有进程的Finish[i]=true都满足, 则表示系统处于安全状态;否则,系统处于不安全状态
*/

void initsafety(int n, int m, int work[MAXM], char Finish[MAXN], int Available[MAXM]) {
	for (int i = 0; i < m; i++) {
		work[i] = Available[i];
	}

	for (int i = 0; i < n; i++)
		Finish[i] = 'F';
}

int safety(int n, int m, int Allocation[][MAXM], int Need[][MAXM], int Available[MAXM], char name[][2]) {
	int work[MAXM];
	char Finish[MAXN];
	initsafety(n, m, work, Finish, Available);//初始化work
	int flag = 0;
	int elem[MAXN];
	int k = 0;
	for (int i = 0; i < n; i++) {
		if (Finish[i] == 'F') {
			for (int j = 0; j < m; j++) {
				if (Need[i][j] <= work[j]) {
					flag = 1;//找到了 当进程Pi获得资源后,可顺利执行,直至完成,并释放出分配给它的资源,故应执行:
					work[j] = work[i] + Allocation[i][j];
					Finish[i] = 'T';
					elem[k++] = i;
				}
			}
		}
	}
	if (flag == 0) {//没找到 
		for (int i = 0; i < n; i++) {
			if (Finish[i] != 'T')
				return -1;//系统不安全
		}
	}
	
	return 1; //系统安全
}
void request(int n, int m, int Requesti[MAXM]) {
	printf("输入进程请求资源数量\n");
	for (int i = 0; i < m; i++) {
		scanf("%d", &Requesti[i]);
	}
}
/*
* (1)如果Requesti[j]≤Need[i,j],便转向步骤(2);否则认为出错,因为它所需要的资源数已超过它所宣布最大值。
(2)如果Requesti[j]≤Available[j],便转向步骤(3);否则,表示尚无足够资源,Pi须等待。 
(3)系统试探着把资源分配给进程Pi,并修改下面数据结构中的数值:
Available[j]=Available[j]-Requesti[j];
Allocation[i,j]=Allocation[i,j]+Requesti[j];  
Need[i,j]=Need[i,j]-Requesti[j];

系统执行安全性算法,检查此次资源分配后,系统是否处于安全状态。若安全,
才正式将资源分配给进程Pi,以完成本次分配;否则,将本次的试探分配作废,恢复原来的资源分配状态,让进程Pi等待
*/
void work(int n, int m, char name[MAXN][2], int Need[][MAXM], int Available[MAXM], int Requesti[MAXM], int Allocation[][MAXM]) {
	printf("输入想要申请请求资源分配的进程名称\n");
	char ch[2];
	getchar();
	scanf("%c%c", &ch[0], &ch[1]);
	int i = 0;
	for (; i < n; i++) {
		if (name[i][0] == ch[0] && name[i][1] == ch[1])
			break;
	}
	if (i == n) {
		printf("输入进程不存在\n");
		return -1;
	}
	request(n, m, Requesti);

	for (int j = 0; j < m; j++) {
		if (Requesti[j] <= Need[i][j]) {
			if (Requesti[j] <= Available[j]) {
				Available[j] = Available[j] - Requesti[j];
				Allocation[i][j] = Allocation[i][j] + Requesti[j];
				Need[i][j] = Need[i][j] - Requesti[j];
				int ret = safety(n, m, Allocation, Need, Available, name);
				if (ret == -1) {//系统不安全 撤销当前操作
					Available[j] = Available[j] + Requesti[j];
					Allocation[i][j] = Allocation[i][j] - Requesti[j];
					Need[i][j] = Need[i][j] + Requesti[j];
					printf("此进程不能执行\n");
				}
			}
			else {
				printf("表示尚无足够资源,进程须等待\n");
				break;
			}
		}
		else {
			printf("所需要的资源数已超过它所宣布最大值,进程不能分配资源\n");
			break;
		}
	}
}
int main() {
	int n = 0;
	printf("输入进程数量,要求小于%d\n", MAXN);
	scanf("%d", &n);
	int m = 0;
	printf("输入资源种类数目,要求小于%d\n", MAXM);
	scanf("%d", &m);

	//1)可利用资源向量Available
			//是个含有m个元素的数组,其中的每一个元素代表一类可利用的资源数目。如果Available[j] = K,则表示系统中现有Rj类资源K个。
	int Available[MAXN];
	//2)最大需求矩阵Max
	//	这是一个n×m的矩阵,它定义了系统中n个进程中的每一个进程对m类资源的最大需求。
	// 如果Max[i, j] = K,则表示进程i需要Rj类资源的最大数目为K。
	int Max[MAXN][MAXM];
	//	3)分配矩阵Allocation
	//	这也是一个n×m的矩阵,它定义了系统中每一类资源当前已分配给每一进程的资源数。
	// 如果Allocation[i, j] = K,则表示进程i当前已分得Rj类资源的数目为K。
	int Allocation[MAXN][MAXM];
	//	4)需求矩阵Need。
	//	这也是一个n×m的矩阵,用以表示每一个进程尚需的各类资源数。
	// 如果Need[i, j] = K,则表示进程i还需要Rj类资源K个,方能完成其任务。
	//Need[i, j] = Max[i, j] - Allocation[i, j]
	int Need[MAXN][MAXM];
	//(5)name数组:存储进程名
	char Name[MAXN][2];
	init(n, m, Name, Max, Allocation);//初始化
	initNeed(n, m, Max, Allocation, Need);//计算需求矩阵
	print(n, m, Name, Max, Allocation, Need);

	initAvailable(n, m, Available, Allocation);//初始化总资源
	printAvailable(n, m, Available);
	int Requesti[MAXM];//申请的资源
	int ret = safety(n, m, Allocation, Need, Available, Name);//安全性检查
	if (ret == -1) {
		printf("系统处于不安全状态,需要重新赋值\n");
		return 0;
	}
	while (1) {
		int i = 0;
		printf("选择是否继续进行资源分配:0表示退出,1表示继续程序\n");
		scanf("%d", &i);
		if (i == 1) {
			work(n, m, Name, Need, Available, Requesti, Allocation);
			print(n, m, Name, Max, Allocation, Need);
			printAvailable(n, m, Available);
			continue;
		}
		else if(i==0) {
			printf("退出程序\n");
			break;
		}
		else {
			printf("输入错误,重新输入\n");
			continue;
		}

	}
	return 0;
}

死锁检测和解除

死锁检测

1、设置某一种数据结构来保存对资源的请求和分配信息

2、提供某种算法来利用这个数据结构存储的信息来检测是否存在死锁

资源分配图

死锁定理:当且仅当资源分配图不可以完全简化时产生死锁

 死锁解除

 在上图中,P1和P2进程陷入死锁,解决死锁的办法有

1、资源剥夺法

暂时挂起(将进程放置到外存)某些死锁进程,将这个死锁进程的资源释放,将这些进程分配给其余的死锁进程,让其余死锁进程可以运行

2、撤销进程法

强制撤销某些或者全部的死锁进程,并将死锁进程的资源释放

3、进程回退法

回退某些死锁进程,让这些死锁进程回到足以避免死锁的位置

 

  • 8
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值