死锁
死锁是指子啊一组进程中的各个进程均占有不会释放的资源,但因互相申请被其它进程所占用不会释放的资源而处于的一种永久等待状态。
死锁的四个必要条件
- 互斥条件:一个资源每次只能被一个执行流使用;
- 请求与保持条件:一个执行流因请求资源而阻塞时,对已获得的资源保持不放;
- 不可剥夺条件:一个执行流已获得的资源,在未使用完之前,不能强行剥夺;
- 循坏等待条件:若干执行流之间形成一种头尾相接的循环等待资源的关系;
避免死锁
- 破坏死锁的四个必要条件;
- 加锁顺序;
- 避免锁未释放的场景;
- 资源一次性分配
避免死锁算法
银行家算法
银行家算法是最著名的死锁避免算法。它提出的思想是:把操作系统看做是银行家,操作系统管理的资源相当于银行家管理的资金,进程向操作系统请求分配资源相当于用户向银行家贷款。操作系统按照银行家制定的规则为进程分配资源,当进程首次申请资源时,要测试该进程对资源的最大需求量,如果系统现存的资源可以满足它的最大需求量则按当前的申请量分配资源,否则就推迟分配。当进程在执行中继续申请资源时,先测试该进程已占用的资源数与本次申请的资源数之和是否超过了该进程对资源的最大需求量。若超过则拒绝分配资源,若没有超过则再测试系统现存的资源能否满足该进程尚需的最大资源量,若能满足则按当前的申请量分配资源,否则也要推迟分配。
- 执行步骤
设Request i是进程Pi的请求向量,如果Request i[j]=K,表示进程P i需要K个R j类型的资源。当P i发出资源请求后,系统按下述步骤进行检查:
(1) 如果Request i[j]≤Need[i,j],便转向步骤(2);否则认为出错,因为它所需要的资源数已超过它所宣布的最大值。
(2) 如果Request i[j]≤Available[j],便转向步骤(3);否则,表示尚无足够资源,Pi须等待。
(3) 系统试探着把资源分配给进程P i,并修改下面数据结构中的数值:
Available[j]:= Available[j]-Request i[j];
Allocation[i,j]:= Allocation[i,j]+Request i[j];
Need[i,j]:= Need[i,j]-Request i[j];
(4) 系统执行安全性算法,检查此次资源分配后系统是否处于安全状态。若安全,才正式将资源分配给进程Pi,以完成本次分配;否则,将本次的试探分配作废,恢复原来的资源分配状态,让进程Pi等待。 - 安全性算法设计
系统所执行的安全性算法可描述如下:
(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[j]+Allocation[i,j];
Finish[i]:=true;
go to step (2);
(4) 如果所有进程的Finish[i]=true都满足,则表示系统处于安全状态;否则,系统处于不安全状态。 - 数据结构
(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当前已分得R j类资源的数目为K。
(4) 需求矩阵Need。这也是一个n×m的矩阵,用以表示每一个进程尚需的各类资源数。如果Need[i,j]=K,则表示进程i还需要R j类资源K个,方能完成其任务。
上述三个矩阵间存在下述关系:Need[i, j]=Max[i, j]-Allocation[i, j]
- 实现代码:
# define _CRT_SECURE_NO_WARNINGS 1
# include <stdio.h>
# include <stdlib.h>
# include <assert.h>
# define TRUE 1 //状态位
# define FAULSE 0 //状态位
# define PCB_NUM 5 //进程数
# define RESOURCE_NUM 5 //资源种类
size_t Menu(); //菜单
void InitPCB(); //初始化程序
size_t SafeCheck(); //安全性算法
void RequestResource(); //发出资源请求
size_t g_max[PCB_NUM][RESOURCE_NUM] = { 0 }; //最大需求矩阵
size_t g_allocation[PCB_NUM][RESOURCE_NUM] = { 0 }; //已分配矩阵
size_t g_need[PCB_NUM][RESOURCE_NUM] = { 0 }; //需求矩阵
size_t g_available[RESOURCE_NUM] = { 0 }; //可利用资源向量
size_t g_work[RESOURCE_NUM] = { 0 }; //可利用资源数目
size_t g_finish[RESOURCE_NUM]; //状态
size_t g_safe_order[PCB_NUM]; //安全序列
size_t g_request[RESOURCE_NUM] = { 0 }; //请求向量
size_t g_pcb_num = 0, g_resource_type = 0; //实际的进程数和资源种类
//菜单函数
size_t Menu()
{
size_t choose = 0;
printf("\t*-*-*-*-*-*- BankerAlgorthm -*-*-*-*-*-*-*-*\n");
printf("\t*-*-*- -*-*-*\n");
printf("\t*-*-*- 1. 初始化进程 -*-*-*\n");
printf("\t*-*-*- 2. 安全性算法 -*-*-*\n");
printf("\t*-*-*- 3. 银行家算法 -*-*-*\n");
printf("\t*-*-*- 0. 退 出 -*-*-*\n");
printf("\t*-*-*- -*-*-*\n");
printf("\t*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\n\n");
printf("请选择->: ");
scanf("%d", &choose);
return choose;
}
//检查初始化是否正确
static int _CheckInit()
{
size_t i = 0, j = 0;
for (i = 0; i < g_pcb_num; i++)
{
for (j = 0; j < g_resource_type; j++)
{
if (g_allocation[i][j] + g_need[i][j] > g_max[i][j])
{
return -1;
}
}
}
return 1;
}
//初始化程序
void InitPCB()
{
size_t i = 0, j = 0;
printf("\n请输入进程数量和资源种类的个数:\n");
fflush(stdin);//清空缓冲区
scanf("%d%d", &g_pcb_num, &g_resource_type);
printf("pcb_num = %d resource_type = %d \n", g_pcb_num, g_resource_type);
printf("\n输入各个进程的最大需求矩阵Max:\n");
fflush(stdin);
for (i = 0; i < g_pcb_num; i++)
{
printf("P[%d]:", i);
for (j = 0; j < g_resource_type; j++)
{
scanf("%d", &g_max[i][j]);
}
}
printf("输入各个进程的已分配矩阵All:\n");
fflush(stdin);
for (i = 0; i < g_pcb_num; i++)
{
printf("P[%d]:", i);
for (j = 0; j < g_resource_type; j++)
{
scanf("%d", &g_allocation[i][j]);
}
}
printf("输入各个进程的需求矩阵Need:\n");
fflush(stdin);
for (i = 0; i < g_pcb_num; i++)
{
printf("P[%d]:", i);
for (j = 0; j < g_resource_type; j++)
{
scanf("%d", &g_need[i][j]);
}
}
//求Available
printf("输入剩余各类资源Avali:\n");
fflush(stdin);
for (i = 0; i < g_resource_type; i++)
{
printf("R[%d]:", i);
scanf("%d", &g_available[i]);
}
int ret = _CheckInit();
if (-1 == ret)
{
printf("初始化失败,分配矩阵与需求矩阵之和大于最大需求矩阵!\n\n");
}
else
printf("初始化成功!\n\n");
}
//打印安全序列
static void _Print()
{
size_t i = 0;
printf("\n在该时刻存在一个安全序列: ");
for (i = 0; i < g_pcb_num; i++)
{
printf("P[%d]", g_safe_order[i]);
if (i != g_pcb_num - 1)
printf("->");
}
printf("\n\n");
}
//安全性算法
size_t SafeCheck()
{
size_t i = 0, j = 0, k = 0;
size_t count, flag;
size_t suffix = 0; //安全序列的下标
//初始化向量Work和Finish
for (i = 0; i < g_resource_type; i++)
g_work[i] = g_available[i];
for (j = 0; j < g_pcb_num; j++)
g_finish[j] = FAULSE;
//查找安全序列
while (1)
{
for (i = 0; i < g_pcb_num; i++)
{
count = 0;
flag = 0;
for (j = 0; j < g_resource_type; j++)
{
if (g_work[j] >= g_need[i][j])
count++;
else
break;
}
//可以进行分配并完成该进程
if ((count == g_resource_type) && (g_finish[i] != TRUE))
{
flag = 1;
for (k = 0; k < g_resource_type; k++)
{
g_work[k] = g_work[k] + g_allocation[i][k];
}
g_finish[i] = TRUE;
g_safe_order[suffix++] = i ;
if (suffix == g_pcb_num)
{
_Print();
return 1;
}
}
}
//遍历完之后没有符合的进程则跳出循环
if (0 == flag)
{
printf("\n不存在安全序列!\n\n");
return 0;
}
else
i = 0;
}
}
//打印分配后的进程资源表
static void _PrintPcbList()
{
size_t i = 0, j = 0;
printf("进程\tMax\tAll\tNeed\tAvail\n");
for (i = 0; i < g_pcb_num; i++)
{
printf("P[%d]:", i);
for (j = 0; j < g_resource_type; j++)
{
printf("%d ", g_max[i][j]);
}
printf("\t");
for (j = 0; j < g_resource_type; j++)
{
printf("%d ", g_allocation[i][j]);
}
printf("\t");
for (j = 0; j < g_resource_type; j++)
{
printf("%d ", g_need[i][j]);
}
printf("\t");
if (0 == i)
{
for (j = 0; j < g_resource_type; j++)
{
printf("%d ", g_available[j]);
}
}
printf("\n");
}
printf("\n\n");
}
//试分配
static void _TryAllocation(size_t PCB_ORDER)
{
size_t i = 0, j = 0;
size_t ret;
for (i = 0; i < g_resource_type; i++)
{
g_available[i] -= g_request[i];
g_allocation[PCB_ORDER][i] += g_request[i];
g_need[PCB_ORDER][i] -= g_request[i];
}
ret = SafeCheck();
//分配失败
if (0 == ret)
{
printf("该分配不安全\n\n", PCB_ORDER);
for (i = 0; i < g_resource_type; i++)
{
g_need[PCB_ORDER][i] += g_request[i];
g_allocation[PCB_ORDER][i] -= g_request[i];
g_available[i] += g_request[i];
}
}
//打印分配后的进程资源表
_PrintPcbList();
}
//发出资源请求
void RequestResource()
{
size_t i = 0;
size_t PCB_ORDER = 0;
printf("\n请输入发出资源请求的进程名:\n");
scanf("%d", &PCB_ORDER);
fflush(stdin);
for (i = 0; i < g_resource_type; i++)
{
printf("Request_%c:", 65 + i);
scanf("%d", &g_request[i]);
}
for (i = 0; i < g_resource_type; i++)
{
//当Request>Need的情况
if (g_request[i]>g_need[PCB_ORDER][i])
{
printf("\n需要的资源已经超出所需的最大值!\n\n");
return;
}
//当Request>Available的情况
if (g_request[i]>g_available[i])
{
printf("\n尚无足够资源\n\n");
return;
}
}
//试分配
_TryAllocation(PCB_ORDER);
}
int main()
{
size_t ret = 0;
while (1)
{
switch (ret = Menu())
{
case 1:
InitPCB();
break;
case 2:
SafeCheck();
break;
case 3:
RequestResource();
break;
case 0:
exit(EXIT_SUCCESS);
break;
default:
break;
}
}
system("pause");
return 0;
}