【操作系统】死锁处理-银行家算法

简介: 【操作系统】死锁处理-银行家算法


一. 实验目的

(1)深入了解操作系统的安全状态和不安全状态;

(2)了解如何避免死锁;

(3)银行家算法是一种最有代表性的避免死锁的算法,掌握其原理及程序实现方法

二. 实验内容

(1)用银行家算法实现资源分配:假定系统中有5个进程{P0, P1, P2, P3, P4}和3类资源{A, B, C},各类资源的数量分别为10、5、7。进程可以动态申请资源、释放资源,系统按进程的申请动态分配资源,要求程序具有显示和打印各进程的某一个时刻的资源分配表和安全序列;显示和打印各进程依次要求申请的资源号以及为某进程分配资源后的有关资源数据。

三. 实验步骤

(1)编写C程序:

#include<stdio.h>
#include<string.h>
typedef struct process{
    char name[2];
    int max[4],allocation[4],need[4];
    bool flag;
}p;
void countNeed(p pro[],int available[],int available_01[],int proNumber,int sourNumber);
int checkSafe(p pro[],int available[],int available_01[],int proNumber,int sourNumber,char requireName[],int requireSource[]);
void printAll(p pro[],int available[],int proNumber,int sourNumber);
int main(){
    int proNumber,sourNumber,flag,i,j;
    scanf("%d",&proNumber);
    scanf("%d",&sourNumber);
    int available[sourNumber],available_01[sourNumber],requireSource[sourNumber];
    p pro[proNumber];
    char requireName[2];
    //初始化资源总数
    for(i=0;i<sourNumber;i++){
        scanf("%d",&available[i]);
    }
    //初始化进程的资源使用情况
    for(i=0;i<proNumber;i++){
        scanf("%s",&pro[i].name);
        pro[i].flag = false;
        for(j=0;j<sourNumber;j++){
            available_01[j] = available[j];
            scanf("%d",&pro[i].max[j]);
        }
        for(j=0;j<sourNumber;j++){
            scanf("%d",&pro[i].allocation[j]);
        }
    }
    //初始化请求进程及其资源请求数
    scanf("%s",&requireName);
    for(j=0;j<sourNumber;j++){
            scanf("%d",&requireSource[j]);
        }
    countNeed(pro,available,available_01,proNumber,sourNumber);
    flag = checkSafe(pro,available,available_01,proNumber,sourNumber,requireName,requireSource);
    if(flag == 0){
        printf("可以找到安全序列,可以分配。\n");
        printAll(pro,available_01,proNumber,sourNumber);
    }
    if(flag == 1){
        printf("查无此进程。\n");
        printAll(pro,available_01,proNumber,sourNumber);
    }
    if(flag == 2){
        printf("需求不合理,不予分配。\n");
        printAll(pro,available_01,proNumber,sourNumber);
    }
    if(flag == 3){
        printf("剩余资源不足,不予分配。\n");
        printAll(pro,available_01,proNumber,sourNumber);
    }
    if(flag == 4){
        printf("找不到安全序列,不予分配。\n");
        printAll(pro,available_01,proNumber,sourNumber);
    }
    return 0;
}
void countNeed(p pro[],int available[],int available_01[],int proNumber,int sourNumber){
    int i,j;
    for(i=0;i<proNumber;i++){
        for(j=0;j<sourNumber;j++){
            pro[i].need[j] = pro[i].max[j] - pro[i].allocation[j];
            available[j] -= pro[i].allocation[j];
            available_01[j] = available[j];
        }
    }
}
int checkSafe(p pro[],int available[],int available_01[],int proNumber,int sourNumber,char requireName[],int requireSource[]){
    int i,j,sum=0,sum1=0,sum2=0,count=0,countRequire=-1;
    bool flagAll = false,flagAll_01 = false;
    //进行名称和请求资源数和need资源数的比较
    for(i=0;i<proNumber;i++){
        if(strcmp(requireName,pro[i].name) == 0) {
            countRequire=i;
            for(j=0;j<sourNumber;j++){
                if(requireSource[j]<=pro[i].need[j]) sum1++;
                if(requireSource[j]<=available[j]) sum2++;
        }
    }
}
    //printf("%d %d %d \n",countRequire,sum1,sum2);
    //countRequire != -1存在进程名称相等的进程
    if(countRequire != -1&&sum1 == sourNumber &&sum2 == sourNumber){
      //对请求的进程进行初始化 
      for(j=0;j<sourNumber;j++){
            available[j] -= requireSource[j];
                pro[countRequire].allocation[j] += requireSource[j];
                pro[countRequire].need[j] -= requireSource[j];
        }
        while(sum<proNumber){
         for(i=0;i<proNumber;i++){
          sum1 = 0;
            if(pro[i].flag == false){
                 for(j=0;j<sourNumber;j++){
                    if(pro[i].need[j]<=available[j]) sum1++;
                    }
            if(sum1 == sourNumber) {
                    for(j=0;j<sourNumber;j++)
                    available[j] += pro[i].allocation[j];
            pro[i].flag = true;
            sum++;
        } 
      }
    }
        count+=6;
        if(count == 54) break;
  }
    }
    else if(countRequire == -1){
        return 1; //1.若输入的进程的名字不正确,输出”查无此进程。“并输出当前系统状态。
    }else if(sum1 != sourNumber) return 2; //2.若申请的资源数目大于最大需求,输出”需求不合理,不予分配。“并输出当前系统状态。
    else if(sum2 != sourNumber) return 3; //3.若申请的资源数目大于剩余资源,输出”剩余资源不足,不予分配。“并输出当前系统状态。
    if(sum == proNumber) {
       for(j=0;j<sourNumber;j++){
        available_01[j] -=  requireSource[j];
     }
    return 0;  //给人家分配!
}
    else if(sum != proNumber) {
      for(j=0;j<sourNumber;j++){
        pro[countRequire].allocation[j] -= requireSource[j];
            pro[countRequire].need[j] += requireSource[j];
     }
  return 4; //4.若找不到安全序列,输出”找不到安全序列,不予分配。“并输出当前系统状态。
}
}
void printAll(p pro[],int available[],int proNumber,int sourNumber){
    printf("name max allocation need available\n");
    int i,j;
    for(i=0;i<proNumber;i++){
        printf("%s ",pro[i].name);
        for(j=0;j<sourNumber;j++){
            printf("%d ",pro[i].max[j]);
        }
        printf("| ");
        for(j=0;j<sourNumber;j++){
            printf("%d ",pro[i].allocation[j]);
        }
        printf("| ");
        for(j=0;j<sourNumber;j++){
            printf("%d ",pro[i].need[j]);
        }
        if(i == 0){
            printf("| ");
            for(j=0;j<sourNumber;j++){
                if(j == sourNumber-1)
            printf("%d",available[j]);
                else printf("%d ",available[j]);
        }
       }else printf("|");
        printf("\n");
    }
}

四. 实验结果

五. 实验总结

银行家算法(Banker’s Algorithm)是一种用于避免死锁的资源分配算法,由荷兰计算机科学家Edsger Dijkstra在1965年提出。它的名字源于银行家在分配贷款时需要考虑资金的分配和回收。

银行家算法基于以下假设:每个进程都需要声明其对各类资源的最大需求量,系统有限数量的资源可供分配。银行家算法通过分析系统当前状态,判断是否存在安全序列,从而决定是否分配资源,以避免死锁发生。

具体而言,银行家算法分为两个阶段:安全性检查和资源分配。在安全性检查阶段,系统通过模拟分配资源给进程,并逐步回收,来判断是否存在安全序列。如果存在安全序列,即使分配资源后可能出现死锁,系统也会继续分配资源。否则,系统会拒绝分配资源,以避免死锁。在资源分配阶段,系统会根据安全性检查的结果分配资源给进程。

银行家算法的核心是安全性检查。安全性检查通过判断资源分配的可行性来避免死锁。它基于安全序列的概念,即一个进程执行完毕并释放资源后,系统能够找到一种资源分配的顺序,使得所有进程都能够正常执行完毕。如果存在安全序列,那么系统就可以继续分配资源;否则,系统会等待,直到存在安全序列。

银行家算法的优点是能够避免死锁,保证系统的安全性。但它的缺点是资源的分配需要满足严格的限制条件,可能导致资源利用率降低。

总之,银行家算法是一种用于避免死锁的资源分配算法,通过分析系统状态和判断安全序列来决定资源分配。它是操作系统中的重要算法之一,能够确保系统的安全性,提高系统的可靠性。

目录
相关文章
|
2月前
|
算法 调度 UED
探索操作系统的心脏:调度算法的奥秘与影响
【10月更文挑战第9天】 本文深入探讨了操作系统中至关重要的组件——调度算法,它如同人体的心脏,维持着系统资源的有序流动和任务的高效执行。我们将揭开调度算法的神秘面纱,从基本概念到实际应用,全面剖析其在操作系统中的核心地位,以及如何通过优化调度算法来提升系统性能。
|
25天前
|
算法 调度 Python
深入理解操作系统中的进程调度算法
在操作系统中,进程调度是核心任务之一,它决定了哪个进程将获得CPU的使用权。本文通过浅显易懂的语言和生动的比喻,带领读者了解进程调度算法的重要性及其工作原理,同时提供代码示例帮助理解。
|
4月前
|
算法 安全
操作系统中的死锁
【8月更文挑战第23天】
52 0
|
1月前
|
算法 大数据 Linux
深入理解操作系统之进程调度算法
【10月更文挑战第24天】本文旨在通过浅显易懂的语言,带领读者深入了解操作系统中的进程调度算法。我们将从进程的基本概念出发,逐步解析进程调度的目的、重要性以及常见的几种调度算法。文章将通过比喻和实例,使复杂的技术内容变得生动有趣,帮助读者建立对操作系统进程调度机制的清晰认识。最后,我们还将探讨这些调度算法在现代操作系统中的应用和发展趋势。
|
2月前
|
算法 调度 UED
深入理解操作系统的进程调度算法
【10月更文挑战第7天】在操作系统的心脏——内核中,进程调度算法扮演着至关重要的角色。它不仅影响系统的性能和用户体验,还直接关系到资源的合理分配。本文将通过浅显易懂的语言和生动的比喻,带你一探进程调度的秘密花园,从最简单的先来先服务到复杂的多级反馈队列,我们将一起见证算法如何在微观世界里编织宏观世界的和谐乐章。
|
2月前
|
边缘计算 算法 调度
探究操作系统的心脏:调度算法的进化与影响
【10月更文挑战第2天】 本文深入探讨了操作系统中核心组件——调度算法的历史演变、关键技术突破及其对现代计算的影响。通过详细回顾从单任务到多任务、实时系统及分布式计算环境下调度算法的发展,文章揭示了这些算法如何塑造我们的数字世界,并对未来的趋势进行了展望。不同于传统的摘要,本文特别聚焦于技术细节与实际应用的结合点,为读者提供一幅清晰的技术演进蓝图。
66 4
|
2月前
|
算法 调度 UED
探索操作系统的心脏:进程调度算法
【9月更文挑战第32天】在数字世界的每一次心跳中,都隐藏着一个不为人知的英雄——进程调度算法。它默默地在后台运作,确保我们的命令得到快速响应,应用程序平稳运行。本文将带你走进操作系统的核心,一探进程调度的奥秘,并通过代码示例揭示其背后的智慧。准备好跟随我一起深入这趟技术之旅了吗?让我们开始吧!
|
3月前
|
算法 调度
操作系统的心脏:深入解析进程调度算法
本文旨在深入探讨现代操作系统中的核心功能之一——进程调度。进程调度算法是操作系统用于分配CPU时间片给各个进程的机制,以确保系统资源的高效利用和公平分配。本文将详细介绍几种主要的进程调度算法,包括先来先服务(FCFS)、短作业优先(SJF)、时间片轮转(RR)以及优先级调度(PS)。我们将分析每种算法的基本原理、优缺点及其适用场景。同时,本文还将讨论多级反馈队列(MFQ)调度算法,并探讨这些算法在实际应用中的表现及未来发展趋势。通过深入解析这些内容,希望能够为读者提供对操作系统进程调度机制的全面理解。
|
3月前
|
存储 算法 前端开发
深入理解操作系统:进程调度与优先级队列算法
【9月更文挑战第25天】在操作系统的复杂世界中,进程调度是维持系统稳定运行的核心机制之一。本文将深入探讨进程调度的基本概念,分析不同的进程调度算法,并着重介绍优先级队列算法的原理和实现。通过简洁明了的语言,我们将一起探索如何优化进程调度,提高操作系统的效率和响应速度。无论你是计算机科学的初学者还是希望深化理解的专业人士,这篇文章都将为你提供有价值的见解。
|
3月前
|
人工智能 算法 大数据
探究操作系统的心脏:调度算法的进化与影响
本文深入探讨了操作系统中核心组件——调度算法的发展及其对系统性能的影响。通过分析先来先服务、短作业优先、时间片轮转等传统调度算法,阐述了它们的原理和优缺点。同时,讨论了现代调度算法如多级队列和优先级调度在提高系统响应速度和处理能力方面的作用。文章还探讨了实时系统中的调度挑战,以及如何通过优化调度策略来满足不同应用场景下的性能需求。
下一篇
DataWorks