线程死锁

======================================================================================================================================================

线程死锁

什么是死锁?

在多道程序系统中,虽可借助于多个进程的并发执行,来改善系统的资源利用率,提高系统的吞吐量,但可能发生一种危险━━死锁。所谓死锁(Deadlock),是指多个进程在运行中因争夺资源而造成的一种僵局(Deadly_Embrace),当进程处于这种僵持状态时,若无外力作用,它们都将无法再向前推进。一组进程中,每个进程都无限等待被该组进程中另一进程所占有的资源,因而永远无法得到的资源,这种现象称为进程死锁,这一组进程就称为死锁进程。

由于资源占用是互斥的,当某个进程提出申请资源后,使得有关进程在无外力协助下,永远分配不到必需的资源而无法继续运行,这就产生了一种特殊现象死锁。一种情形,此时执行程序中两个或多个线程发生永久堵塞(等待),每个线程都在等待被其他线程占用并堵塞了的资源。例如,如果线程A锁住了记录1并等待记录2,而线程B锁住了记录2并等待记录1,这样两个线程就发生了死锁现象。计算机系统中,如果系统的资源分配策略不当,更常见的可能是程序员写的程序有错误等,则会导致进程因竞争资源不当而产生死锁的现象。

排除方法:

1,撤消陷于死锁的全部进程; 
2,逐个撤消陷于死锁的进程,直到死锁不存在; 
3,从陷于死锁的进程中逐个强迫放弃所占用的资源,直至死锁消失; 
4,从另外一些进程那里强行剥夺足够数量的资源分配给死锁进程,以解除死锁状态。

死锁原理

死锁可以定义为一组相互竞争系统资源或进行通信的进程间的“永久”阻塞。当一组进程中每个线程都在等待某个事件(典型的就是等待所请求的资源被释放),而只有这组进程的其他被阻塞的进程才可以触发该事件的发生,这是这时就称为这组进程发生死锁。因为没有事件能够被触发,所以死锁是永久性的。

死锁的条件:

1, 互斥条件:一个资源每次只能被一个进程使用。 
2, 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。 
3, 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。 
4, 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

如何处理死锁?

1>死锁预防 
简单来讲就是设计一种系统来排除死锁的可能性。可以把死锁预防分为两大类:一种间接死锁预防,即防止前面三个条件的任何一个的发生;另一种是直接死锁预防,即防止循环等待的发生。下面我们来具体分析:

  • 互斥:如果要对资源进行互斥访问,那么系统必须支持互斥,就有可能发生死锁,比如文件,允许多个读访问,但只能允许互斥的写访问,这种情况下,如果多个进程申请权限,就有可能发生死锁。

  • 占有且等待:为预防占有且等待,可要求进程一次性的申请所有的资源,并且阻塞这个进程直到所有请求都得到满足。这个方法有可能很低效,有可能一个进程被阻塞很长时间申请资源,但是其实只需要一部分资源就可以继续执行;另外分配的资源可能长时间不被使用,但也不会被释放,也就不能被其他进程使用;另一个问题就是一个进程不可能事先就知道他所需要的所有资源。

  • 不可抢占:有几种方法可以预防这个条件,如果一个进程继续申请资源被拒绝,那么它要释放最初占用的资源,如果有必要,再次申请;另外如果一个进程申请当前被另一个进程占用的资源,则操作系统可以强行占用另一个系统的资源,要求他释放。

  • 循环等待:可以定义资源的线性顺序来预防。如果一个进程已经分配到了某一类型的资源,那么它只能申请排在这一类型后面的资源。

2>死锁避免 
死锁避免允许三个必要的条件,但通过明智的选择,永远不会达到死锁点,这就是死锁避免。它比死锁预防允许更多的并发,例如:如果一个进程请求会导致死锁,则不启动此进程。另如果一个进程申请的资源会导致进程死锁,则不允许分配资源。

算法的实现

1, 初始化 由用户输入数据,分别对可利用资源向量矩阵AVAILABLE、最大需求矩阵MAX、分配矩阵ALLOCATION、需求矩阵NEED赋值。 
2,银行家算法 在避免死锁的方法中,所施加的限制条件较弱,有可能获得令人满意的系统性能。在该方法中把系统的状态分为安全状态和不安全状态,只要能使系统始终都处于安全状态,便可以避免发生死锁。 银行家算法的基本思想是分配资源之前,判断系统是否是安全的;若是,才分配。它是最具有代表性的避免死锁的算法。 设进程cusneed提出请求REQUEST ,则银行家算法按如下规则进行判断。

  • 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>系统执行安全性检查,如安全,则分配成立;否则试探险性分配作废,系统恢复原状,进程等待。

3,安全性检查算法 1>设置两个工作向量Work=AVAILABLE;FINISH 2>从进程集合中找到一个满足下述条件的进程, FINISH==false; NEED<=Work; 如找到,执行3>;否则,执行4> 3>设进程获得资源,可顺利执行,直至完成,从而释放资源。 Work+=ALLOCATION; Finish=true; GOTO 2 。 
4,如所有的进程Finish= true,则表示安全;否则系统不安全。

避免死锁算法:

#include "string.h"
#include "iostream"
using namespace std;
#define FALSE 0
#define TRUE 1
#define W 10
#define R 20
int M ; //总进程数
int N ; //资源种类
int ALL_RESOURCE[W];//各种资源的数目总和
int MAX[W][R]; //M个进程对N类资源最大资源需求量
int AVAILABLE[R]; //系统可用资源数
int ALLOCATION[W][R]; //M个进程已经得到N类资源的资源量
int NEED[W][R]; //M个进程还需要N类资源的资源量
int Request[R]; //请求资源个数
void showdata() //函数showdata,输出资源分配情况
{
int i,j;
cout<<"各种资源的总数量(all):"<<endl;
cout<<" ";
for (j=0;j<N;j++)cout<<"资源"<<j<<": "<<ALL_RESOURCE[j];
cout<<endl<<endl;
cout<<"系统目前各种资源可用的数为(available):"<<endl;
cout<<" ";
for (j=0;j<N;j++)cout<<"资源"<<j<<": "<<AVAILABLE[j];
cout<<endl<<endl;
cout<<"各进程还需要的资源量(need):"<<endl<<endl;
cout<<"资源0"<<"资源1"<<"资源2"<<endl;
for (i=0;i<M;i++)
for (i=0;i<M;i++)
{
cout<<"进程p"<<i<<": ";
for (j=0;j<N;j++)cout<<NEED[i][j]<<" ";;
cout<<endl;
}
cout<<endl;
cout<<" 各进程已经得到的资源量(allocation): "<<endl<<endl;
cout<<"资源0"<<"资源1"<<"资源2"<<endl;
for (i=0;i<M;i++)
{
cout<<"进程p"<<i<<": ";
for (j=0;j<N;j++)cout<<ALLOCATION[i][j]<<" ";
cout<<endl;
}
cout<<endl;
}
void changdata(int k) //函数changdata,改变可用资源和已经拿到资源和还需要的资源的值
{
int j;
for (j=0;j<N;j++)
{
AVAILABLE[j]=AVAILABLE[j]-Request[j];
ALLOCATION[k][j]=ALLOCATION[k][j]+Request[j];
NEED[k][j]=NEED[k][j]-Request[j];
}
}
void rstordata(int k) //函数rstordata,恢复可用资源和已经拿到资源和还需要的资源的值
{
int j;
for (j=0;j<N;j++)
{
AVAILABLE[j]=AVAILABLE[j]+Request[j];
ALLOCATION[k][j]=ALLOCATION[k][j]-Request[j];
NEED[k][j]=NEED[k][j]+Request[j];
}
}
int chkerr(int s) //函数chkerr,检查是否安全
{ int WORK,FINISH[W];
int i,j,k=0;
for(i=0;i<M;i++)FINISH[i]=FALSE;
for(j=0;j<N;j++)
{
WORK=AVAILABLE[j];
i=s;
do
{
if(FINISH[i]==FALSE&&NEED[i][j]<=WORK)
{
WORK=WORK+ALLOCATION[i][j];
FINISH[i]=TRUE;
i=0;
}
else
{
i++;
}
}while(i<M);
for(i=0;i<M;i++)
if(FINISH[i]==FALSE)
{
cout<<endl;
cout<<"系统不安全!!! 本次资源申请不成功!!!"<<endl;
cout<<endl;
return 1;
}
}
cout<<endl;
cout<<" 经安全性检查,系统安全,本次分配成功。"<<endl;
cout<<endl;
return 0;
}
void bank() //银行家算法
{
int i=0,j=0;
char flag='Y';
while(flag=='Y'||flag=='y')
{
i=-1;
while(i<0||i>=M)
{
cout<<" 请输入需申请资源的进程号(从P0到P"<<M-1<<",否则重输入!):";
cout<<"p";cin>>i;
if(i<0||i>=M)cout<<" 输入的进程号不存在,重新输入!"<<endl;
}
cout<<" 请输入进程P"<<i<<"申请的资源数:"<<endl;
for (j=0;j<N;j++)
{
cout<<" 资源"<<j<<": ";
cin>>Request[j];
if(Request[j]>NEED[i][j]) //若请求的资源数大于进程还需要i类资源的资源量j
{
cout<<" 进程P"<<i<<"申请的资源数大于进程P"<<i<<"还需要"<<j<<"类资源的资源量!";
cout<<"申请不合理,出错!请重新选择!"<<endl<<endl;
flag='N';
break;
}
else
{
if(Request[j]>AVAILABLE[j]) //若请求的资源数大于可用资源数
{
cout<<" 进程P"<<i<<"申请的资源数大于系统可用"<<j<<"类资源的资源量!";
cout<<"申请不合理,出错!请重新选择!"<<endl<<endl;
flag='N';
break;
}
}
}
if(flag=='Y'||flag=='y')
{
changdata(i); //调用changdata(i)函数,改变资源数
if(chkerr(i)) //若系统安全
{
rstordata(i); //调用rstordata(i)函数,恢复资源数
showdata(); //输出资源分配情况
}
else //若系统不安全
showdata(); //输出资源分配情况
}
else //若flag=N||flag=n
{
showdata();
cout<<endl;
cout<<" 是否继续银行家算法演示,按'Y'或'y'键继续,按'N'或'n'键退出演示: ";
cin>>flag;
}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值