〔重庆理工大学〕操作系统实验报告【实验四 死锁解决实验】
摘要:本实验报告研究了死锁避免问题,通过银行家算法实现资源分配的安全性检查。实验首先分析了死锁产生的四个必要条件,详细介绍了银行家算法的核心概念和计算流程。在具体实验中,模拟了系统资源分配场景,计算了初始Need矩阵和Available向量,执行了安全性检查并得出安全序列。报告还处理了两个资源请求场景,通过伪代码填空和C++编程验证了算法实现。实验结果表明,银行家算法能有效避免死锁,保证系统安全运
实验四 避免死锁实验(实验报告)
班级:123030201
学号:1230904XXXX
姓名:段 X X
| 课程目标 | 目标3得分(功能实现情况) | 目标4得分(自主学习和解决问题能力情况) |
|---|---|---|
| 自评分 | 95 | 95 |
| 批阅分 |
CQUT操作系统实验报告【实验四 死锁解决实验】
一、实验目的
-
理解死锁的概念和产生条件
-
掌握银行家算法的基本原理
-
学会应用银行家算法进行资源分配的安全性检查
-
培养自主学习解决实际资源分配问题的能力
二、实验原理
(一)死锁产生的四个必要条件
-
互斥条件:资源不能被共享
-
请求并保持条件:进程持有资源并等待其他资源
-
不可剥夺条件:资源不能被强制剥夺
-
循环等待条件:存在进程资源的循环等待链
(二)银行家算法核心概念
-
可用资源向量:Available
-
最大需求矩阵:Max
-
分配矩阵:Allocation
-
需求矩阵:Need = Max - Allocation
三、实验内容
实验场景:计算机系统资源分配模拟,用银行家算法分析避免死锁
(一)初始系统状态
系统资源:A(3)、B(7)、C(11)
T0时刻进程资源情况:
| 进程 | 最大需求(Max) | 已分配(Allocation) | 需求(Need) | 完成状态 |
|---|---|---|---|---|
| P0 | (0, 0, 4) | (0, 0, 3) | (0, 0, 1) | □ |
| P1 | (1, 7, 5) | (1, 0, 0) | (0, 7, 5) | □ |
| P2 | (2, 3, 5) | (1, 3, 5) | (1, 0, 0) | □ |
| P3 | (0, 6, 4) | (0, 0, 2) | (0, 6, 2) | □ |
| P4 | (0, 6, 5) | (0, 0, 1) | (0, 6, 4) | □ |
| 当前可用资源:Available = (1, 4, 0) |
(二)实验步骤
第一步:计算初始Need矩阵和Available向量
计算过程:
Need[i] = Max[i] - Allocation[i]
-
P0: Need = (0-0, 0-0, 4-3) = (0, 0, 1)
-
P1: Need = (1-1, 7-0, 5-0) = (0, 7, 5)
-
P2: Need = (2-1, 3-3, 5-5) = (1, 0, 0)
-
P3: Need = (0-0, 6-0, 4-2) = (0, 6, 2)
-
P4: Need = (0-0, 6-0, 5-1) = (0, 6, 4)
Available = 总资源 - ∑Allocation[i]
-
总资源:(3, 7, 11)
-
∑Allocation[i]:(0+1+1+0+0, 0+0+3+0+0, 3+0+5+2+1) = (2, 3, 11)
-
Available = (3-2, 7-3, 11-11) = (1, 4, 0)
第二步:执行安全性算法
安全性检查表:
| 步骤 | 进程 | Work | Need(≤ Work?) | Work + Allocation | 完成状态 |
|---|---|---|---|---|---|
| 1 | P2 | (1, 4, 0) | 是(1, 0, 0 ≤ 1, 4, 0) | (1+1, 4+3, 0+5) = (2, 7, 5) | 完成 |
| 2 | P0 | (2, 7, 5) | 是(0, 0, 1 ≤ 2, 7, 5) | (2+0, 7+0, 5+3) = (2, 7, 8) | 完成 |
| 3 | P1 | (2, 7, 8) | 是(0, 7, 5 ≤ 2, 7, 8) | (2+1, 7+0, 8+0) = (3, 7, 8) | 完成 |
| 4 | P3 | (3, 7, 8) | 是(0, 6, 2 ≤ 3, 7, 8) | (3+0, 7+0, 8+2) = (3, 7, 10) | 完成 |
| 5 | P4 | (3, 7, 10) | 是(0, 6, 4 ≤ 3, 7, 10) | (3+0, 7+0, 10+1) = (3, 7, 11) | 完成 |
| 安全序列:⟨P2, P0, P1, P3, P4⟩ |
第三步:资源请求处理
场景1:T0时刻后进程P1请求资源 Request = (0, 2, 0)
-
检查 Request ≤ Need? ☑是 □否(0≤0,2≤7,0≤5)
-
检查 Request ≤ Available? ☑是 □否(0≤1,2≤4,0≤0)
模拟分配后的状态:
-
Available = (1, 4, 0) - (0, 2, 0) = (1, 2, 0)
-
Allocation[1] = (1, 0, 0) + (0, 2, 0) = (1, 2, 0)
-
Need[1] = (0, 7, 5) - (0, 2, 0) = (0, 5, 5)
执行安全性检查:
☑ 系统处于安全状态 □ 系统处于不安全状态
安全序列:⟨P2, P0, P1, P3, P4⟩
决策:☑ 同意分配 □ 拒绝分配
场景2:T0时刻后进程P3请求资源 Request = (0, 4, 0)
-
检查 Request ≤ Need? ☑是 □否(0≤0,4≤6,0≤2)
-
检查 Request ≤ Available? ☑是 □否(0≤1,4≤4,0≤0)
模拟分配并检查安全性:
决策:□ 同意分配 ☑ 拒绝分配
理由:模拟分配后系统仍存在安全序列,资源分配不会导致死锁。
思考:T0时刻系统处于安全状态的系统资源最小值是:(3, 6, 11)
第四步:伪代码填空
函数 安全性检查():
工作向量 = 可用资源
完成标记 = [假, 假, 假, ...]
循环 直到没有进程可执行为止:
找到这样一个进程i:
完成标记[i] = 假
需求[i] <= 工作向量 # 填空
如果找到:
工作向量 = 工作向量 + 分配[i] # 填空
完成标记[i] = 真 # 填空
加入安全序列
否则:
跳出循环
如果所有进程都完成:
返回 真 # 填空
否则:
返回 假 # 填空
第五步:编程验证
#include <stdio.h>
#define N 5 // 进程数
#define M 3 // 资源类型数
// 安全性检查函数,返回1表示安全,0表示不安全,seq存储安全序列
int safetyCheck(int Max[N][M], int Allocation[N][M], int Need[N][M], int Available[M], int seq[N]) {
int Work[M];
int finish[N] = {0};
int count = 0;
// 初始化工作向量
for (int i = 0; i < M; i++) {
Work[i] = Available[i];
}
while (count < N) {
int found = 0;
for (int i = 0; i < N; i++) {
if (!finish[i]) {
// 检查Need[i] ≤ Work
int ok = 1;
for (int j = 0; j < M; j++) {
if (Need[i][j] > Work[j]) {
ok = 0;
break;
}
}
if (ok) {
// 分配资源,更新Work
for (int j = 0; j < M; j++) {
Work[j] += Allocation[i][j];
}
finish[i] = 1;
seq[count++] = i;
found = 1;
}
}
}
if (!found) break; // 无可用进程,跳出循环
}
return count == N ? 1 : 0;
}
// 资源请求处理函数
int requestResource(int pid, int Request[M], int Max[N][M], int Allocation[N][M], int Need[N][M], int Available[M]) {
// 检查Request ≤ Need
for (int i = 0; i < M; i++) {
if (Request[i] > Need[pid][i]) {
return 0;
}
}
// 检查Request ≤ Available
for (int i = 0; i < M; i++) {
if (Request[i] > Available[i]) {
return 0;
}
}
// 模拟分配
for (int i = 0; i < M; i++) {
Available[i] -= Request[i];
Allocation[pid][i] += Request[i];
Need[pid][i] -= Request[i];
}
// 安全性检查
int seq[N];
if (safetyCheck(Max, Allocation, Need, Available, seq)) {
return 1; // 安全,同意分配
} else {
// 不安全,回滚分配
for (int i = 0; i < M; i++) {
Available[i] += Request[i];
Allocation[pid][i] -= Request[i];
Need[pid][i] += Request[i];
}
return 0; // 拒绝分配
}
}
int main() {
// 初始数据定义
int Max[N][M] = {
{0, 0, 4},
{1, 7, 5},
{2, 3, 5},
{0, 6, 4},
{0, 6, 5}
};
int Allocation[N][M] = {
{0, 0, 3},
{1, 0, 0},
{1, 3, 5},
{0, 0, 2},
{0, 0, 1}
};
int Need[N][M];
int Available[M];
// 计算需求矩阵
printf("计算Need矩阵:\n");
for (int i = 0; i < N; i++) {
printf("P%d: ", i);
for (int j = 0; j < M; j++) {
Need[i][j] = Max[i][j] - Allocation[i][j];
printf("%d ", Need[i][j]);
}
printf("\n");
}
// 计算初始Available向量
int totalResource[M] = {3, 7, 11};
int allocSum[M] = {0};
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
allocSum[j] += Allocation[i][j];
}
}
for (int j = 0; j < M; j++) {
Available[j] = totalResource[j] - allocSum[j];
}
printf("\n初始Available向量: (%d, %d, %d)\n", Available[0], Available[1], Available[2]);
// 初始安全性检查
int seq[N];
if (safetyCheck(Max, Allocation, Need, Available, seq)) {
printf("初始系统安全,安全序列: ");
for (int i = 0; i < N; i++) {
printf("P%d ", seq[i]);
}
printf("\n");
} else {
printf("初始系统不安全\n");
}
// 处理P1的资源请求(0,2,0)
int pid1 = 1;
int req1[M] = {0, 2, 0};
printf("\n处理P%d的请求(%d, %d, %d):\n", pid1, req1[0], req1[1], req1[2]);
if (requestResource(pid1, req1, Max, Allocation, Need, Available)) {
printf("同意分配\n");
} else {
printf("拒绝分配\n");
}
// 处理P3的资源请求(0,4,0)
int pid2 = 3;
int req2[M] = {0, 4, 0};
printf("\n处理P%d的请求(%d, %d, %d):\n", pid2, req2[0], req2[1], req2[2]);
if (requestResource(pid2, req2, Max, Allocation, Need, Available)) {
printf("同意分配\n");
// 输出分配后的安全序列
safetyCheck(Max, Allocation, Need, Available, seq);
printf("分配后安全序列: ");
for (int i = 0; i < N; i++) {
printf("P%d ", seq[i]);
}
printf("\n");
} else {
printf("拒绝分配\n");
}
return 0;
}
四、实验结果分析
(一)实验运行验证情况

实验运行后,输出结果包含 Need 矩阵、初始 Available 向量、安全序列及对 P1 和 P3 资源请求的处理决策,与预期结果一致,验证了算法的正确性。
(二)初始状态安全性
-
安全序列:⟨P2, P3, P4, P0, P1⟩
-
系统是否安全:☑是 □否
(三)资源请求分析
| 请求场景 | 是否安全 | 安全序列 | 分配决策 |
|---|---|---|---|
| P1(0, 2, 0) | ☑是 □否 | ⟨P2, P0, P1, P3, P4⟩ | ☑同意 □拒绝 |
| P3(0, 4, 0) | ☑是 □否 | ⟨P2, P0, P3, P1, P4⟩ | □同意 ☑拒绝 |
五、讨论
(一)除了银行家算法,还有哪些死锁处理策略?
-
死锁预防:破坏死锁的四个必要条件之一,如资源预分配(破坏持有并等待)、资源有序分配(破坏循环等待)、允许资源剥夺(破坏不可剥夺)。
-
死锁检测:定期执行死锁检测算法,识别死锁进程与资源,通过终止进程或剥夺资源解除死锁。
-
死锁忽略:不主动处理死锁,依赖用户或管理员手动干预(适用于死锁概率极低的场景,如个人计算机)。
(二)请讨论在实际系统中死锁处理的工程权衡
-
资源利用率与安全性:预防死锁会降低资源利用率(如预分配导致资源闲置),银行家算法需提前知晓最大需求,实际中难以完全满足。
-
开销与复杂度:检测死锁需额外计算资源依赖关系,解除死锁可能导致数据丢失;忽略死锁虽无额外开销,但可能因死锁导致系统不稳定。
-
场景适配:嵌入式系统优先选择简单的预防策略(低复杂度),服务器系统倾向于检测+解除(平衡利用率与稳定性),个人PC多采用忽略策略(低成本)。
六、实验报告(电子版Word文档)
1.操作系统实验报告【实验四 死锁解决实验】
更多推荐



所有评论(0)