操作系统实验之银行算法

news2024/11/27 5:30:34

一、实验目的

        采用高级语言编写一个动态分配系统资源的程序,模拟死锁现象,观察死锁发生的条件,并采用适当的算法,有效地防止死锁的发生。

二、实验内容

        本次实验采用银行算法防止死锁的发生。设有3个并发进程共享10个系统资源。在3个进程申请系统资源之和不超过10时,当然不可能发生死锁,因为各个进程资源都能满足。在有一个进程申请的系统资源数超过10时,必然会发生死锁。应该排队这两种情况。程序采用人工输入各进程的申请资源序列。如果随机给各进程分配资源,就可能发生死锁,这也就是不采用防止死锁算法的情况。假如,按照一定的规则,为各进程分配资源,就可以防止死锁的发生。

三、实验步骤

3.1任务分析

3.1.1 实验任务

  1. 设计一个几个并发进程共享m个系统资源的系统。进程可动态的申请资源和释放资源,系统按各进程的申请动态的分配资源。
  2. 系统应能显示各进程申请和释放资源的过程,能显示系统动态分配资源的过程,便于观察和分析。
  3. 系统应能选择是否采用防止死锁的算法,应设计多种防止死锁的算法,并能任意选择其中任何一种投入运行,同时要求,在不采用防止死锁算法时观察死锁现象发生的过程,在使用防止死锁的算法时,了解在同样条件下防止死锁发生的过程。

3.2 概要设计

抽象数据类型的定义:

1)资源:

属性:名称(name)、数量(amount)

操作:

初始化资源(InitResource(name, amount))

获取资源名称(GetName())

获取资源数量(GetAmount())

设置资源数量(SetAmount(amount))

2)进程:

属性:进程编号(ID)、最大需求资源(Max)、已分配资源(Allocation)、还需资源(Need)

操作:

初始化进程(InitProcess(ID, Max, Allocation))

获取进程编号(GetID())

获取最大需求资源矩阵(GetMax())

获取已分配资源矩阵(GetAllocation())

获取还需资源矩阵(GetNeed())

3)系统状态:

属性:可用资源(Available)、进程集合(Processes)

操作:

初始化系统状态(InitSystemState(Available, Processes))

获取可用资源矩阵(GetAvailable())

获取进程集合(GetProcesses())

c3837dac7de2429e9db14ed2c0e5dc94.png

主程序流程:

  1. 初始化系统状态:

输入资源种类数量和初始资源量、进程数量、每个进程的最大资源需求、已分配给每个进程的资源

  1. 显示初始系统状态:

调用显示系统状态函数(ShowSystemState())

  1. 安全性检查:

调用安全性算法函数(CheckSafety())

  1. 功能选择循环:

进入功能选择循环,直到用户选择离开。用户可以选择增加资源、删除资源、修改资源、分配资源、增加作业等功能

 

程序模块调用关系:

主程序根据用户选择调用相应的功能函数

  1. 增加资源:调用增加资源函数(AddResource())
  2. 删除资源:调用删除资源函数(DeleteResource())
  3. 修改资源:调用修改资源函数(ModifyResource())
  4. 分配资源:调用分配资源函数(AllocateResource())
  5. 增加作业:调用增加作业函数(AddJob())

c604fef8707048749d27a9f78b26e2c1.png 

3.3详细设计 

银行算法:顾名思义是来源于银行的借贷业务,一定数量的本金要应付各种客户的借贷周转,为了防止银行因资金无法周转而倒闭,对每一笔贷款,必须考察其最后是否能归还。研究死锁现象时就碰到类似的问题,有限资源为多个进程共享,分配不好就会发生每个进程都无法继续下去的死锁僵局。

银行算法的原理是先假定某一次分配成立,然后检查由于这次分配是否会引起死锁,即剩下的资源是不是能满足任一进程完成的需要。如这次分配是安全的(不会引起死锁),就实施本次分配,再作另一种分配试探,一直探索到各进程均满足各自的资源请求,防止了死锁的发生。

主要函数设计:

main() 函数作为程序的入口,首先提示用户输入系统资源种类和数量,并进行初始化。用户需要输入作业数量和每个进程的最大需求量,以及每个进程已经申请的资源量。程序提供了一个菜单,让用户选择不同的功能,如增加资源、删除资源、修改资源、分配资源、增加作业等。

de02aa4f350e4671881584b270e3bc25.png

showdata函数用于展示当前系统的资源分配状况,包括每个进程的最大需求、已分配资源和尚需资源。

changdata函数用于变更资源分配情况,主要在资源请求得到批准后调用。

 603c6e9d45184937ba9f56eaa477e55a.png

safe函数实现了银行家算法的核心,即安全性算法。这个函数检查在当前资源分配情况下,系统是否处于安全状态。使得每个进程都可以按需求获得资源,执行完毕后释放资源,从而避免死锁。 

42b79a9142e8428b824b6aebd4e3a964.png 

share函数处理资源请求,首先检查请求是否合理(即请求量不超过需求量和可用量),然后尝试分配资源,并调用safe函数检查系统是否仍然安全。

addresources、delresources、changeresources和addprocess函数提供了添加、删除、修改资源和添加作业的功能,以适应动态变化的资源需求。

f7ce4da09b78460981d0def28f8ca4fd.png

3.4调试分析

改进设想:

  1. 引入异常处理机制,处理用户输入错误、系统状态异常等情况,提高程序的健壮性。
  2. 在用户输入时进行更严格的检查,防止非法输入导致程序崩溃或不稳定。

 3.5测试结果

4c0574e81a844859ae27d2e37e33432f.png

40c5daa88ec7401c96cced4311c2f49c.png

63a0758479744878be91ba276635263b.png

28b660eabd234b75919b70557c8effa0.png

bc924bfe31dd4009abb8c4cd95695ec6.png

cb62856c7f2c425c93056d7fa1f684ab.png

eb2fecb20eb1433f9645d5e46870bf3e.png

测试结果和预期相同

3.6使用说明

运行程序,输入系统可供资源种类数量,名称,资源数量

b9f9b124328a4275b1e1af9d84dd1fa2.png

输入作业数量,各进程最大需求量,已申请的资源量

0a411935c00441369cb7cbf8d6f6127b.png

输出系统目前可用资源,以及各进程资源分配

9be266bc30cc42768ce49298bcf0c4ed.png

根据需求选择功能

ad6dda2fd8ab4a5e971b66915e28a2f2.png

四、实验总结

        通过本次实验,我学习了。在实践中,我通过代码实现和调试更深刻地理解了银行家算法的工作原理和优缺点,也更直观的了解死锁发生的原因,初步掌握防止死锁、解除死锁的简单方法,加深理解教材中有关死锁的内容。

       银行家算法是用于避免死锁的一种资源分配算法,它根据系统的状态和进程的资源需求来判断是否能够安全地分配资源。其可以有效地避免了死锁情况的发生,通过检查资源分配的请求,只有在分配资源不会导致系统不安全状态时才进行分配。并且确保只有在系统能够提供足够资源的情况下,才会分配资源给进程,保证资源的合理利用。但是由于算法会保留一部分资源以应对未来可能的请求,因此可能导致资源的浪费。除此之外,在每次资源请求时进行安全性检查,这可能会引入一定的开销。

        这次实验不仅让我更加熟悉操作系统的内部机制,也为我今后深入学习操作系统和计算机体系结构提供了基础。也意识到操作系统的设计和优化是一个复杂而细致的工作,需要综合考虑各种因素,权衡不同的算法和策略。

五、附录

#include <stdio.h>
#include <string.h>
#define False 0
#define True 1
#define MAX 100

int Max[MAX][MAX] = {0};          // 各进程所需各类资源的最大需求
int Avaliable[MAX] = {0};         // 系统可用资源
char name[MAX] = {0};             // 资源的名称
int Allocation[MAX][MAX] = {0};   // 系统已分配资源
int Need[MAX][MAX] = {0};         // 还需要资源
int Request[MAX] = {0};           // 请求资源向量
int temp[MAX] = {0};              // 存放安全序列
int Work[MAX] = {0};              // 存放系统可提供资源
int M = 100;                      // 作业的最大数为100
int N = 100;                      // 资源的最大数为100

void showdata();                  // 显示资源矩阵
int changdata(int i);             // 进行资源分配
int safe();                       // 安全性算法
void share();                     // 利用银行家算法对申请资源对进行判定
void addresources();              // 添加资源
void delresources();              // 删除资源
void changeresources();           // 修改资源
void addprocess();                // 添加作业

int main() {
    int i, j, number, choice, m, n, flag;
    char ming;

    // 输入系统可供资源种类数量和初始资源量
    printf("***********************************\n");
    printf("系统可供资源种类数量:");
    scanf("%d", &n);
    N = n;
    for (i = 0; i < n; i++) {
        printf("资源%d名称:", i + 1);
        scanf(" %c", &ming);
        name[i] = ming;
        printf("资源数量:");
        scanf("%d", &number);
        Avaliable[i] = number;
    }

    // 输入进程数量
    printf("作业数量:");
    scanf("%d", &m);
    M = m;

    // 输入每个进程的最大资源需求
    printf("各进程的最大需求量(%d*%d矩阵)[Max]:\n", m, n);
    for (i = 0; i < m; i++) {
        for (j = 0; j < n; j++) {
            scanf("%d", &Max[i][j]);
            Need[i][j] = Max[i][j];
        }
    }

    // 输入已分配给每个进程的资源,并验证输入的合法性
    do {
        flag = 0;
        printf("各进程已经申请的资源量(%d*%d矩阵)[Avaliable]:\n", m, n);
        for (i = 0; i < m; i++) {
            for (j = 0; j < n; j++) {
                scanf("%d", &Allocation[i][j]);
                if (Allocation[i][j] > Max[i][j]) {
                    flag = 1;
                }
                Need[i][j] = Max[i][j] - Allocation[i][j];
            }
        }
        if (flag) {
            printf("申请的资源大于最大需求量,请重新输入!\n");
        }
    } while (flag);

    showdata();
    safe();

    choice = 1;

    // 菜单驱动循环,提供不同的功能选项
    while (choice) {
        printf("\n");
        printf("1:增加资源    \n");
        printf("2:删除资源    \n");
        printf("3:修改资源    \n");
        printf("4:分配资源    \n");
        printf("5:增加作业    \n");
        printf("0:离开        \n");
        printf("*\n");
        printf("请选择功能:");
        scanf("%d", &choice);

        switch (choice) {
            case 1:
                addresources();
                break;
            case 2:
                delresources();
                break;
            case 3:
                changeresources();
                break;
            case 4:
                share();
                break;
            case 5:
                addprocess();
                break;
            case 0:
                choice = 0;
                break;
            default:
                printf("请正确选择功能(0-5)\n");
                break;
        }
    }

    return 1;
}

// 显示当前资源和进程状态的函数
void showdata() {
    int i, j;
    printf("系统目前可用的资源[Avaliable]:\n");
    for (i = 0; i < N; i++) {
        printf("%c ", name[i]);
    }
    printf("\n");
    for (j = 0; j < N; j++) {
        printf("%d ", Avaliable[j]);
    }
    printf("\n");
    printf("      Max  Allocation  Need\n");
    printf("进程名  ");
    for (j = 0; j < 3; j++) {
        for (i = 0; i < N; i++) {
            printf("%c ", name[i]);
        }
        printf("      ");
    }
    printf("\n");
    for (i = 0; i < M; i++) {
        printf(" %d     ", i);
        for (j = 0; j < N; j++) {
            printf("%d ", Max[i][j]);
        }
        printf("      ");
        for (j = 0; j < N; j++) {
            printf("%d ", Allocation[i][j]);
        }
        printf("      ");
        for (j = 0; j < N; j++) {
            printf(" %d ", Need[i][j]);
        }
        printf("\n");
    }
}

// 当资源分配给进程时更新资源分配和需求的函数
int changdata(int i) {
    int j;
    for (j = 0; j < M; j++) {
        Avaliable[j] = Avaliable[j] - Request[j];
        Allocation[i][j] = Allocation[i][j] + Request[j];
        Need[i][j] = Need[i][j] - Request[j];
    }
    return 1;
}

// 使用银行家算法检查系统是否处于安全状态的函数
int safe() {
    int i, k = 0, m, apply, Finish[MAX] = {0};
    int j;
    int flag = 0;

    // 使用可用资源初始化Work数组
    Work[0] = Avaliable[0];
    Work[1] = Avaliable[1];
    Work[2] = Avaliable[2];

    // 检查进程是否能够完成而不会导致死锁
    for (i = 0; i < M; i++) {
        apply = 0;
        for (j = 0; j < N; j++) {
            if (Finish[i] == False && Need[i][j] <= Work[j]) {
                apply++;
                if (apply == N) {
                    for (m = 0; m < N; m++) {
                        Work[m] = Work[m] + Allocation[i][m];
                    }
                    Finish[i] = True;
                    temp[k] = i;
                    i = -1;
                    k++;
                    flag++;
                }
            }
        }
    }

    for (i = 0; i < M; i++) {
        if (Finish[i] == False) {
            printf("系统不安全\n");
            return -1;
        }
    }

    printf("系统是安全的\n");
    printf("分配的序列:");
    for (i = 0; i < M; i++) {
        printf("%d", temp[i]);
        if (i < M - 1) {
            printf("->");
        }
    }
    printf("\n");
    return 0;
}

// 分配资源的函数
void share() {
    char ch;
    int i = 0, j = 0;
    ch = 'y';

    printf("请输入要求分配的资源进程号(0-%d):", M - 1);
    scanf("%d", &i);
    printf("请输入进程 %d 申请的资源:\n", i);
    for (j = 0; j < N; j++) {
        printf("%c:", name[j]);
        scanf("%d", &Request[j]);
    }

    for (j = 0; j < N; j++) {
        if (Request[j] > Need[i][j]) {
            printf("进程 %d 申请的资源大于它需要的资源 分配不合理,不予分配!\n", i);
            ch = 'n';
            break;
        } else {
            if (Request[j] > Avaliable[j]) {
                printf("进程 %d 申请的资源大于系统现在可利用的资源 分配出错,不予分配!\n", i);
                ch = 'n';
                break;
            }
        }
    }

    if (ch == 'y') {
        changdata(i);
        showdata();
        safe();
    }
}

// 添加资源的函数
void addresources() {
    int n, flag;
    printf("请输入需要添加资源种类的数量:");
    scanf("%d", &n);
    flag = N;
    N = N + n;
    for (int i = 0; i < n; i++) {
        printf("名称:");
        scanf(" %c", &name[flag]);
        printf("数量:");
        scanf("%d", &Avaliable[flag++]);
    }
    showdata();
    safe();
}

// 删除资源的函数
void delresources() {
    char ming;
    int i, flag = 1;
    printf("请输入需要删除的资源名称:");
    do {
        scanf(" %c", &ming);
        for (i = 0; i < N; i++) {
            if (ming == name[i]) {
                flag = 0;
                break;
            }
        }
        if (i == N) {
            printf("该资源名称不存在,请重新输入:");
        }
    } while (flag);

    for (int j = i; j < N - 1; j++) {
        name[j] = name[j + 1];
        Avaliable[j] = Avaliable[j + 1];
    }

    N = N - 1;
    showdata();
    safe();
}

// 修改资源的函数
void changeresources() {
    printf("系统目前可用的资源[Avaliable]:\n");
    for (int i = 0; i < N; i++) {
        printf("%c:%d\n", name[i], Avaliable[i]);
    }
    printf("输入系统可用资源[Avaliable]:\n");
    for (int k = 0; k < N; k++) {
        printf("%c:", name[k]);
        scanf("%d", &Avaliable[k]);
    }
    printf("经修改后的系统可用资源为\n");
    for (int k = 0; k < N; k++) {
        printf("%c:%d\n", name[k], Avaliable[k]);
    }
    showdata();
    safe();
}

// 添加作业的函数
void addprocess() {
    int flag = M;
    M = M + 1;
    printf("请输入该作业的最大需求量[Max]\n");
    for (int i = 0; i < N; i++) {
        printf("%c:", name[i]);
        scanf("%d", &Max[flag][i]);
        Need[flag][i] = Max[flag][i] - Allocation[flag][i];
    }
    showdata();
    safe();
}

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2189999.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

1c语言基础

1.关键字 一、数据类型关键字 A基本数据类型&#xff08;5个&#xff09; void&#xff1a;声明函数无返回值或无参数&#xff0c;声明无类型指针&#xff0c;显式丢弃运算结果char&#xff1a;字符型类型数据&#xff0c;属于整型数据的一种int&#xff1a;整型数据&#x…

Ollama 运行视觉语言模型LLaVA

Ollama的LLaVA&#xff08;大型语言和视觉助手&#xff09;模型集已更新至 1.6 版&#xff0c;支持&#xff1a; 更高的图像分辨率&#xff1a;支持高达 4 倍的像素&#xff0c;使模型能够掌握更多细节。改进的文本识别和推理能力&#xff1a;在附加文档、图表和图表数据集上进…

Github界面学习

之前并没有使用到其他功能大多数是看代码&#xff0c;然后看discussion&#xff1b; now,在做毕设的时候发现了一个gymnasium关于异步环境的bug&#xff0c;查看github发现已经被修复了&#xff1b; 因此希望学习一下修复者是在哪个module修复以及如何修复以及提交代码&#…

Spring Boot框架在大学生就业招聘中的应用

3系统分析 3.1可行性分析 通过对本大学生就业招聘系统实行的目的初步调查和分析&#xff0c;提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本大学生就业招聘系统采用JAVA作为开发语言&#xff0c;S…

kaggle实战3RossmanStore商店销售额预测XgBoost解决回归问题案例1

kaggle实战2信用卡反欺诈逻辑回归模型案例1 数据集下载地址 https://download.csdn.net/download/AnalogElectronic/89844637 https://tianchi.aliyun.com/dataset/89785 加载数据 #预测销售额 回归问题 import numpy as np import pandas as pd import matplotlib.pyplot a…

无神论文解读之ControlNet:Adding Conditional Control to Text-to-Image Diffusion Models

一、什么是ControlNet ControlNet是一种能够控制模型生成内容的方法&#xff0c;能够对文生图等模型添加限制信息&#xff08;边缘、深度图、法向量图、姿势点图等&#xff09;&#xff0c;在当今生成比较火的时代很流行。 这种方法使得能够直接提供空间信息控制图片以更细粒…

招联2025校招内推倒计时

【投递方式】 直接扫下方二维码&#xff0c;或点击内推官网https://wecruit.hotjob.cn/SU61025e262f9d247b98e0a2c2/mc/position/campus&#xff0c;使用内推码 igcefb 投递&#xff09; 【招聘岗位】 后台开发 前端开发 数据开发 数据运营 算法开发 技术运维 软件测试 产品策…

【课程学习】随机过程之泊松过程

随机过程之泊松过程 泊松分布泊松过程 泊松分布 二项分布是离散性的分布&#xff0c;泊松分布是把二项分布取n趋于无穷得到的连续分布。也就是在一段时间内不停的观察某件事情发生的次数。 如&#xff1a;一个小时内观察一段路上经过行人的数目&#xff0c;如果每个半个小时观…

nginx和gateway的关系和区别

在技术选型时&#xff0c;选择 Nginx 和 Spring Cloud Gateway&#xff08;或简称为 Gateway&#xff09;主要取决于具体应用场景和技术需求。下面是两者的一些关键差异和适用场景。 一、Nginx 概念 Nginx 是一个高性能的 Web 服务器和反向代理服务器&#xff0c;常被用作静…

智能手表(Smart Watch)项目

文章目录 前言一、智能手表&#xff08;Smart Watch&#xff09;简介二、系统组成三、软件框架四、IAP_F411 App4.1 MDK工程结构4.2 设计思路 五、Smart Watch App5.1 MDK工程结构5.2 片上外设5.3 板载驱动BSP5.4 硬件访问机制-HWDataAccess5.4.1 LVGL仿真和MDK工程的互相移植5…

CSRF | CSRF 漏洞介绍

关注这个漏洞的其他相关笔记&#xff1a;CSRF 漏洞 - 学习手册-CSDN博客 0x01&#xff1a;CSRF 漏洞简介 CSRF&#xff08;Cross-Site request forgery&#xff0c;跨站请求伪造&#xff09;也被称为 One Click Attack 或者 Session Riding&#xff0c;通常缩写为 CSRF 或者 X…

【Java】IntelliJ IDEA开发环境安装

一、下载 官方地址&#xff1a;https://www.jetbrains.com/idea/ 点击Download直接下载 二、安装 双击安装包&#xff0c;点击Next 选择安装路径&#xff0c;点击Next 勾选安装内容 安装完成。 三、创建项目 打开IDEA&#xff0c;填写项目名称&#xff0c;选择项目安装路径…

S7-200 SMART的数据类型说明

S7-200 SMART的数据主要分为&#xff1a; 与实际输入/输出信号相关的输入/输出映象区&#xff1a; I&#xff1a;数字量输入&#xff08;DI&#xff09;Q&#xff1a;数字量输出&#xff08;DO&#xff09;AI&#xff1a;模拟量输入AQ&#xff1a;模拟量输出 内部数据存储区…

STM32 Hal库SDIO在FATFS使用下的函数调用关系

STM32 Hal库SDIO在FATFS使用下的函数调用关系 本文并不将FATFS的相关接口操作&#xff0c;而是将HAL在使用FATFS通过SDIO外设管理SD卡时&#xff0c;内部函数的调用逻辑&#xff0c;有助于当我们使用CUBEMX生成FATFS读取SD卡的代码时无法运行时Debug。本文也会说明一些可能出现…

如何编写一个优雅的commit message

在Git中&#xff0c;git commit 命令扮演着至关重要的角色。它的主要作用是将暂存区&#xff08;staging area&#xff09;里的改动内容提交到本地仓库&#xff08;repository&#xff09;中&#xff0c;形成一个新的版本或提交&#xff08;commit&#xff09;。这个过程是 Git…

渗透测试入门学习——使用python脚本自动识别图片验证码,OCR技术初体验

写在前面 由于验证码在服务端生成后存储在服务器的session中&#xff0c;而标用于标识用户身份的sessionid存在于用户cookie中 所以本次识别验证码时需要用requests.session()创建会话对象&#xff0c;模拟真实的浏览器行为&#xff0c;保持与服务器的会话才能获取登录时服务…

wsl2 ubuntu 桥接以太网卡

注意&#xff1a;此方法需要至少 Windows 11 22H2。桥接模式就是将主机网卡与虚拟机虚拟的网卡利用虚拟网桥进行通信。 在桥接的作用下&#xff0c;类似于把宿主机虚拟为一个交换机&#xff0c;所有桥接设置的虚拟机连接到这个交换机的一个接口上&#xff0c;宿主机也同样插在这…

通信工程学习:什么是RARP反向地址解析协议

RARP&#xff1a;反向地址解析协议 RARP&#xff08;Reverse Address Resolution Protocol&#xff0c;反向地址解析协议&#xff09;是一种网络协议&#xff0c;其主要作用是在设备只知道物理地址&#xff08;如MAC地址&#xff09;时&#xff0c;允许其从网关服务器的地址解析…

致亲爱的Android studio

你的未来发展趋势&#xff1a; 可不可以把兼容性&#xff0c;什么的搞得更好。起因是我想写期末大作业&#xff0c;然后简单的把功能写的差不多了之后&#xff0c;我就想到处看看有没有一套比较好的类似于组件库的东西&#xff0c;但是没找到&#xff0c;然后就把目标锁定到了G…

Vue入门-Node.js安装

进入Node.js中文网 ​​​​​​​点击进入Node.js中文网 或者手动输入网址&#xff1a; https://www.nodejs.com.cn/download.html 点击下载64位安装包&#xff1a; 下载好之后双击进行安装 可选择个性化安装或默认安装 直接点【Next】按钮&#xff0c;此处可根据个人需求…