饭做大事的人,往往做小事也认真,
而做小事也不认真的人,往往也做不成大事;
所以凡事要认真对待,才能得到自己想要的人生。–周国平
1. 死锁的定义
指在一组进程中的各个进程均占有不会释放的资源,但因为互相申请被其他进程所占用不会释放的资源而处于一种永久等待状态。
也指多个线程对锁资源进行竞争访问,但是因为推进顺序不当,导致相互等待,是程序无法往下运行。
2. 死锁产生的原因
(1) 因为系统资源不足;
(2) 进程运行推进的顺序不合适;
(3) 资源分配不当等,如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则就会因争夺有限的资源而陷入死锁。其次,进程运行推进顺序与速度不同,也可能产生死锁。
3. 死锁的四个必要条件
(1) 互斥条件:一个资源每次只能被一个进程使用。;
(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放;
(3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺;
(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
注意:这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。
4. 如何可以避免死锁
(1)破坏死锁的四个必要条件;
(2)加锁顺序一致;
(3)避免锁未释放的场景;
(4)资源一次性分配。
5. 避免死锁算法数据结构设计
5.1 可利用资源向量矩阵AVAILABLE
这是一个含有m个元素的数组,其中的每一个元素代表一类可利用的资源数目,其初始值是系统中所配置的该类全部可用资源的数目,其数值随该类资源的分配和回收而动态地改变。如果AVAILABLE [j]= K,则表示系统中现有R类资源K个
5.2 最大需求矩阵MAX
这是一个n*m的矩阵,用以表示每一个进程对m类资源的最大需求。如果MAX =K,则表示进程i需要R类资源的数目为K。
5.3 分配矩阵ALLOCATION。这也是一个n*m的矩阵,它定义了系统中每一类资源当前已分配给每一进程的资源数。如果ALLOCATION =K,则表示进程i当前已分得R类资源的数目为K。
5.4 需求矩阵NEED
这也是一个n*m的矩阵,用以表示每一个进程尚需的各类资源数。如果NEED =K,则表示进程i还需要R类资源K个,才能完成其任务。
上述矩阵存在下述关系: NEED = MAX-ALLOCATION
6.避免死锁算法实现
6.1 初始化
由用户输入数据,分别对可利用资源向量矩阵AVAILABLE、最大需求矩阵MAX、分配矩阵ALLOCATION、需求矩阵NEED赋值。
6.2 银行家算法
在避免死锁的方法中,所施加的限制条件较弱,有可能获得令人满意的系统
性能。在该方法中把系统的状态分为安全状态和不安全状态,只要能使系统
始终都处于安全状态,便可以避免发生死锁。 银行家算法的基本思想是分配
资源之前,判断系统是否是安全的;若是,才分配。它是最具有代表性的避免死锁的算法。 设进程cusneed提出请求REQUEST ,则银行家算法按如下规则进行判断。
系统中总的资源,对应可利用资源向量Available
进程运行所需资源,对应最大需求矩阵Max
已经分配的资源数P,对应分配矩阵Allocation
还需要申请的资源数R,对应需求矩阵Need
对应关系:Need=Max-Allocation
(1)如果REQUEST [cusneed] <= NEED[cusneed],则转(2);否则,出错;
(2)如果REQUEST [cusneed] <= AVAILABLE[cusneed],则转(3);否则,出错;
(3)系统试探分配资源,修改相关数据:
AVAILABLE-=REQUEST[cusneed]; ALLOCATION[cusneed]+=REQUEST[cusneed];
NEED[cusneed]-=REQUEST[cusneed];
(4)系统执行安全性检查,如安全,则分配成立;否则试探险性分配作废,系统恢复原状,进程等待。
银行家算法思想:允许用户分批申请资源,每次分配之前,都要检查是否安全。
#include <iostream> using namespace std;
#define MAXPROCESS 50 /*最大进程数*/
#define MAXRESOURCE 100 /*最大资源数*/
int AVAILABLE[MAXRESOURCE]; /*可用资源数组*/
int MAX[MAXPROCESS][MAXRESOURCE]; /*最大需求矩阵*/
int ALLOCATION[MAXPROCESS][MAXRESOURCE]; /*分配矩阵*/
int NEED[MAXPROCESS][MAXRESOURCE]; /*需求矩阵*/
int REQUEST[MAXPROCESS][MAXRESOURCE]; /*进程需要资源数*/
bool FINISH[MAXPROCESS]; /*系统是否有足够的资源分配*/
int p[MAXPROCESS]; /*记录序列*/
int m,n; /*m个进程,n个资源*/ void Init(); bool Safe(); void Bank(); int main()
{
Init();
Safe();
Bank();
}
void Init() /*初始化算法*/
{
int i,j;
cout<<"请输入进程的数目:";
cin>>m;
cout<<"请输入资源的种类:";
cin>>n;
cout<<"请输入每个进程最多所需的各资源数,按照"<<m<<"x"<<n<<"矩阵输入"<<endl;
for(i=0;i<m;i++)
for(j=0;j<n;j++)
cin>>MAX[j];
cout<<"请输入每个进程已分配的各资源数,也按照"<<m<<"x"<<n<<"矩阵输入"<<endl; for(i=0;i<m;i++)
{
for(j=0;j<n;j++)
{
cin>>ALLOCATION[j];
NEED[j]=MAX[j]-ALLOCATION[j];
if(NEED[j]<0)
{
cout<<"您输入的第"<<i+1<<"个进程所拥有的第"<<j+1<<"个资源数错误,请重新输入:"<<endl;
j--;
continue;
}
}
}
cout<<"请输入各个资源现有的数目:"<<endl;
for(i=0;i<n;i++)
{
cin>>AVAILABLE;
}
}
void Bank() /*银行家算法*/
{
int i,cusneed;
char again;
while(1)
{
cout<<"请输入要申请资源的进程号(注:第1个进程号为0,依次类推)"<<endl;
cin>>cusneed;
cout<<"请输入进程所请求的各资源的数量"<<endl;
for(i=0;i<n;i++)
{
cin>>REQUEST[cusneed];
}
for(i=0;i<n;i++)
{
if(REQUEST[cusneed]>NEED[cusneed])
{
cout<<"您输入的请求数超过进程的需求量!请重新输入!"<<endl;
continue;
}
if(REQUEST[cusneed]>AVAILABLE)
{
cout<<"您输入的请求数超过系统有的资源数!请重新输入!"<<endl;
continue;
}
}
for(i=0;i<n;i++)
{
AVAILABLE-=REQUEST[cusneed];
ALLOCATION[cusneed]+=REQUEST[cusneed];
NEED[cusneed]-=REQUEST[cusneed];
}
if(Safe())
{
cout<<"同意分配请求!"<<endl;
}
else
{
cout<<"您的请求被拒绝!"<<endl;
for(i=0;i<n;i++)
{
AVAILABLE+=REQUEST[cusneed];
ALLOCATION[cusneed]-=REQUEST[cusneed];
NEED[cusneed]+=REQUEST[cusneed];
}
}
for(i=0;i<m;i++)
{
FINISH=false;
}
cout<<"您还想再次请求分配吗?是请按y/Y,否请按其它键"<<endl;
cin>>again;
if(again=='y'||again=='Y')
{
continue;
}
break;
}
}
bool Safe()/*安全性算法*/
{
int i,j,k,l=0;
int Work[MAXRESOURCE];/*工作数组*/
for(i=0;i<n;i++)
Work=AVAILABLE;
for(i=0;i<m;i++)
{
FINISH=false;
}
for(i=0;i<m;i++)
{
if(FINISH==true)
{
continue;
}
else
{
for(j=0;j<n;j++)
{
if(NEED[j]>Work[j])
{
break;
}
}
if(j==n)
{
FINISH=true;
for(k=0;k<n;k++)
{
Work[k]+=ALLOCATION[k];
}
p[l++]=i;
i=-1;
}
else
{
continue;
}
}
if(l==m)
{
cout<<"系统是安全的"<<endl;
cout<<"安全序列:"<<endl;
for(i=0;i<l;i++)
{
cout<<p;
if(i!=l-1)
{
cout<<"-->";
}
}
cout<<""<<endl;
return true;
}
}
cout<<"系统是不安全的"<<endl;
return false;
}
6.3 安全性检查算法
(1)设置两个工作向量Work=AVAILABLE;FINISH
(2)从进程集合中找到一个满足下述条件的进程,
FINISH==false;
NEED<=Work;
如找到,执行(3);否则,执行(4)
(3)设进程获得资源,可顺利执行,直至完成,从而释放资源。 Work+=ALLOCATION; Finish=true; GOTO 2
(4)如所有的进程Finish= true,则表示安全;否则系统不安全。