[Linux]死锁
来源:互联网 发布:vb皮肤控件 skinsharp 编辑:程序博客网 时间:2024/05/29 15:11
死锁是指多个进程在运行过程中因争夺资源而造成的一种僵局,当进程处于这种僵持状态时,若无外力作用,它们都将无法再向前推进。之前信号量的时候我们知道,如果多个进程等待,主要体现在占有锁的问题上。死锁也可以被定义为:一组竞争系统资源或互相通信的进程间相互的永久阻塞。当一组进程中的所有进程都在等待一个事件,而只有在进程集合中的其他阻塞的进程才可以触发该事件,这时就称一组进程死锁。因为没有事件触发,因此死锁是永久性的。
产生死锁的原因有:
(1)竞争资源。当系统中供多个进程共享的资源如打印机、公用队列等,其数目不足以满足诸进程的需要时,会引起诸进程对资源的竞争而产生死锁。
(2)进程间推进顺序非法。进程在运行过程中,请求和释放资源的顺序不当,也同样会导致产生进程死锁。
详细分析一下产生死锁的原因哦。
(1)可剥夺和非剥夺性资源
可剥夺性资源指某进程在获得这类资源后,该资源可以再被其他进程或系统剥夺。如优先级高的可以剥夺优先级低的进程的处理机。非剥夺性资源是当这类资源分配给某进程后,再不能强行收回,只能在进程用完后自行释放。
(2)竞争非剥夺性资源
由于它们的数量不能满足诸进程运行的需要,会使进程在运行过程中,因剥夺这些资源而陷入僵局。
比如,系统中有一台打印机R1和一台磁带机R2,供进程P1,P2共享。如果P1占用了打印机,P2占用了磁带机。此时如果P1想使用磁带机,而P2想使用打印机,这就使P1和P2都在等待对方的资源被释放,而陷入僵局。从而也使P1和P2得不到自己的资源而不能释放现有的资源,最后进入死锁状态。
(3)竞争临时性资源
上述的打印机资源属于顺序性重复使用的资源,属于永久性资源。还有一种是临时性资源,是一个进程产生,由另一进程使用短暂时间后无用的资源。也可能产生死锁。
(4)推进顺序不当。P1—>Request(R2),p2—>Request(R1)时产生死锁。
产生死锁的必要条件
如果发生死锁,则有四个产生死锁的必要条件:
(1)互斥条件。一次只有一个进程使用资源,其他进程不能访问已分配的资源。
(2)请求和保持条件(也称占有且等待)。指进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源又已被其他进程占有,此时请求进程阻塞,但又对自己已获得的其他资源保持不放。
(3)不剥夺条件(非抢占)。指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完自己释放。
(4)环路等待(循环等待)。指存在一个封闭的进程链,使得每个资源至少占有此链中下一个进程所需要的一个资源。在发生死锁时,必然存在一个进程,资源的环形链,即P0,P1,P2….Pn,则P0在等待P1占有的资源,P1占有P2的,….Pn占有P0的。
说完死锁之后,我们应该想想如何处理这种死锁呢。处理死锁的基本方法有:预防死锁,避免死锁,检测死锁,解除死锁。
预防死锁是使四个必要条件中的第2,3,4个中的一个不成立来避免不发生死锁。为预防死锁,可以使请求和保持条件中,可以要求进程一次性地请求所有需要的资源,并且阻塞这个进程直到所有请求都同时满足。对于非抢占式的预防死锁的方法,如果占有某些资源的一个进程进行进一步资源请求被拒绝,则该进程必须释放它最初占用的资源,如果有必要,可以再次请求此类资源。还有一种情况是,如果一个进程请求当前被另一个进程占有的一个资源,则操作系统可以抢占另一个进程,要求它释放资源。(这类情况适合具有不同优先级的进程)
死锁避免
解决死锁问题的另一种方法是死锁避免。与死锁预防的差距也不大。这里有俩种死锁避免的方法,
1.如果一个进程的请求会导致死锁,则不启动此进程
2.如果一个进程增加资源的请求导致死锁,则不允许此分配
这里解决死锁问题的方法有:银行家算法
银行家算法通过已分配的资源和可用资源数等来获取安全序列,如果存在安全序列,就可以分配请求资源,不存在则说明不可以请求资源,这样就可以有效的避免死锁。
(1)请求资源,发出请求向量
(2)假定可为P1分配资源,修改Available,Allocation和Need向量
(3)利用安全性算法检查此时系统是否安全
银行家算法需求分析:
允许进程动态地申请资源,系统在每次实施资源分配之前,先计算资源分配的安全性,若此次资源分配安全(即资源分配后,系统能按某种顺序来为每个进程分配其所需的资源,直至最大需求,使每个进程都可以顺利地完成),便将资源分配给进程,否则不分配资源,让进程等待。
功能实现:
理解了死锁的原因,尤其是产生死锁的四个必要条件,就可以最大可能地避免、预防和解除死锁。所以,在系统设计、进程调度等方面注意如何能够不让这四个必要条件成立,如何确定资源的合理分配算法,避免进程永久占据系统资源。此外,也要防止进程在处于等待状态的情况下占用资源,在系统运行过程中,对进程发出的每一个系统能够满足的资源申请进行动态检查,并根据检查结果决定是否分配资源,若分配后系统可能发生死锁,则不予分配,否则予以分配 。因此,对资源的分配要给予合理的规划。
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]
#define _CRT_SECURE_NO_WARNINGS 1extern "C"#include<stdio.h>#include<stdlib.h>#define W 10int Available[W]; //可使用资源int Max[W][W]; //最大需求资源数int Allocation[W][W]; //已分配资源int Need[W][W]; //需求资源int Work[W]; //工作向量int Finish[W]; //是否有足够的资源分配,状态标志int Request[W][W]; //进程申请资源向量int Temp[W]; //暂存可用资源数int AllReSourceNum[W]; //各类资源总数int i, j;int ResourceNum; //系统资源总数int ProcessNum; //总的进程数int a; //当前申请的进程号int l, e; int b = 0, c = 0, f = 0, g; //c: 统计对于每一个进程,成功分配的资源类别数int SecurityCheck() //安全性检测{ printf("\n\n"); printf("\t\t\t 安全性检测 \n\n"); printf(" 工作向量 尚需求量 已分配 工作向量+已分配\n进程 "); for (c = 1; c <= 4; c++) { for (j = 1; j <=ResourceNum; j++) { printf(" %d类", j); } } for (i = 1; i <=ProcessNum; i++) { Temp[i] = Available[i]; //Temp[i]只是一个暂时寄存的中间变量,为防止在下面安全性检查时修改到Available[i]而代替的一维数组 Finish[i] = false; } for (g = 1; g <=ProcessNum; g++) { for (i = 1; i <=ProcessNum; i++) { b = 0; //计数器初始化 Finish[i] == false; for (j = 1; j <=ResourceNum; j++) { if (Need[i][j] <= Temp[j]) { b = b + 1; } if (Finish[i] == false && b ==ResourceNum) { Finish[i] = true; printf("\nP[%d] ", i); //依次输出进程安全序列 for (l = 1; l <=ResourceNum; l++) { printf(" %2d ", Temp[l]); } for (j = 1; j <=ResourceNum; j++) { printf(" %2d ",Need[i][j]); } for (j = 1; j <=ResourceNum; j++) { //Allocation[i][j]=Temp[j]-Need[i][j]; printf(" %2d ", Allocation[i][j]); } for (j = 1; j <=ResourceNum; j++) { printf(" %2d ", Temp[j] + Allocation[i][j]); } for (l = 1; l <=ResourceNum; l++) { Temp[l] = Temp[l] + Allocation[i][l]; } } } } } printf("\n\n"); for (i = 1; i <=ProcessNum; i++) { if (Finish[i] == true) f = f + 1; //统计Finish[i]==true的个数 } if (f ==ProcessNum) { printf("安全序列"); printf("\n\n系统剩余资源量:"); for (i = 1; i <=ResourceNum; i++) { printf(" %d ", Available[i]); } f = 0; //将计数器f重新初始化,为下一次提出新的进程申请做准备 return 1; } else { printf("不安全序列"); return 0; }}void Initialize() //初始化{ printf("请输入系统的资源种类数:"); scanf("%d", &ResourceNum); for (i = 1; i <=ResourceNum; i++) { printf("第%d类资源总数:", i); scanf("%d", &AllReSourceNum[i]); } printf("请输入进程总数:"); scanf("%d", &ProcessNum); for (i = 1; i <=ProcessNum; i++) { for (j = 1; j <=ResourceNum; j++) { printf("进程P[%d]对第%d类资源的最大需求量:", i, j); scanf("%d", &Max[i][j]); } } for (i = 1; i <=ProcessNum; i++) { for (j = 1; j <=ResourceNum; j++) { printf("进程P[%d]对第%d类资源已分配数:", i, j); scanf("%d", &Allocation[i][j]); Need[i][j] = Max[i][j] - Allocation[i][j]; } } for (i = 1; i <=ResourceNum; i++) { for (j = 1; j <=ProcessNum; j++) { AllReSourceNum[i] -= Allocation[j][i]; } } for (i = 1; i <=ResourceNum; i++) Available[i] = AllReSourceNum[i]; SecurityCheck();}void RequestResource() //进程申请资源{ printf("请输入申请资源的进程:"); scanf("%d", &a); for (i = 1; i <=ResourceNum; i++) { printf("请输入进程P[%d]对%d类资源的申请量:", a, i); scanf("%d", &Request[a][i]); if (Request[a][i] >Need[a][i]) { printf("\n出错!进程申请的资源数多于它自己申报的最大需求量\n"); return; } if (Request[a][i] > Available[i]) { printf("\nP[%d]请求的资源数大于可用资源数,必须等待\n", a); return; } } for (i = 1; i <=ResourceNum; i++) { //以下是试探性分配 Available[i] = Available[i] - Request[a][i]; Allocation[a][i] = Allocation[a][i] + Request[a][i]; Need[a][i] =Need[a][i] - Request[a][i]; } int ret=SecurityCheck(); if (ret == 1) { int key = 0; for (j = 1; j <=ResourceNum; j++) { if (Need[a][j] == 0) { key++; } } if (key ==ResourceNum) { for (j = 1; j <=ResourceNum; j++) { Available[j] += Allocation[a][j]; Allocation[a][j] = 0; } } }}void ResourceState(){ printf("\n\n"); printf(" 已分配 最大需求量 尚需要量 \n进程"); for (i = 1; i <= 3; i++) { for (j = 1; j <=ResourceNum; j++) { printf(" %d类", j); } } for (i = 1; i <=ProcessNum; i++) { printf("\nP[%d]", i); for (j = 1; j <=ResourceNum; j++) { printf(" %2d ", Allocation[i][j]); } for (j = 1; j <=ResourceNum; j++) { printf(" %2d ", Max[i][j]); } for (j = 1; j <=ResourceNum; j++) { printf(" %2d ",Need[i][j]); } } printf("\n\n系统剩余资源量: "); for (i = 1; i <=ResourceNum; i++) { printf(" %d ", Available[i]); } printf("\n");}void menu(){ printf("\n\t-------------银行家算法---------------\n"); printf(" 1、初始化 \n"); printf(" 2、进程请求资源 \n"); printf(" 3、资源分配状态 \n"); printf(" 4、退出 \n"); printf("\t--------------------------------------\n"); printf("\n请输入你的选择: ");}//BankerAlth.cpp#include"BankerAlth.h"int main(){ int select = 0; printf("\n\n"); while (1) { menu(); scanf("%d", &select); printf("\n\n"); switch (select) { case 1: Initialize(); break; case 2: RequestResource(); break; case 3: ResourceState(); break; case 4: printf("\nSee you Next time !\n\n"); system("pause"); return 0; } } system("pause"); return 0;}
运行结果:
- Linux-死锁
- linux死锁
- [Linux]死锁
- Linux-死锁
- Linux 进程管理 --------------死锁
- Linux 进程管理 --------------死锁
- deadlock linux死锁
- linux 死锁问题调试
- Linux 死锁例子
- Linux死锁分析
- Linux spi死锁问题
- linux 进程死锁
- Linux的死锁检测
- 【Linux】线程和死锁
- linux 同步机制 死锁
- linux中的死锁
- Linux:死锁问题
- 浅谈Linux死锁检测
- java通过HttpServletRequest获取post请求中的body内容
- 整数排序2
- 计算机名(主机名)、用户账号、系统型号、操作系统
- Java中的内部类02-访问其所在方法中的final类型的局部变量
- Linux入门须知快捷键,Linux常用快捷键,ubuntu常用快捷键,terminate清屏方式,清屏快捷键,进出虚拟机快捷方式
- [Linux]死锁
- 使用Android Studio开发时遇到的问题及解答(持续更新中~~)
- 内部类
- 拉格朗日乘数法
- arcgis——arcCatalog 10.2 创建企业级数据库
- freemarker的使用心得
- iText7报错com.itextpdf.kernel.font.PdfType0Font.getCidFontType2(PdfType0Font.java:720)解决
- 一个非常简单的spring-boot web项目(一)
- 二叉树的递归遍历与非递归遍历