Linux系统编程:死锁的产生和预防(银行家算法)

news/2024/5/20 14:52:41 标签: 死锁, 银行家算法, 死锁检测算法

前言

多个执行流在对多个锁资源进行争抢操作时,因为推进顺序不当导致执行流相互等待,流程无法继续推进,导致死锁

一:死锁的产生

死锁产生的四个必要条件

1. 互斥条件:

同一时间一个锁资源只能被一个执行流加锁,直到释放。

2. 不可剥夺条件:

一个执行流在释放锁资源之前,其他的执行流无法剥夺占用资源。

3. 请求保持条件:

一个执行流请求被占有的锁资源时发生阻塞,还对已经获得的锁资源不进行释放。

4. 环路等待条件:

两个执行流相互请求对方的资源并且不释放已经得到的资源,相互等待。

二:死锁的预防

破坏死锁产生的必要条件

1. 破坏不可剥夺条件:

方法一:如果执行流去抢占资源被拒绝,就释放自己已经获得的资源。
方法二:操作系统允许抢占,只要执行流优先级大,就可以抢到。

2. 破坏请求保持条件:

方法一:将锁资源一次性按顺序进行分配。
方法二:只要有一个资源得不到分配,也不给这个进程分配其他的资源。

3. 破坏环路等待条件:

系统给每类资源赋予一个编号,每一条执行流按编号顺序请求资源。

三:死锁的避免(银行家算法

银行家算法的算法思想:

操作系统当作银行家,操作系统管理的资源相当于银行家管理的资金,进程向操作系统请求资源相当于用户向银行家贷款。

定义两种状态:系统的安全状态和非安全状态。

每一个进程进入系统时,必须申明在运行过程当中,可能需要的每种资源的最大数目。当进程请求一组资源时,系统必须首先确定是否有足够的资源分配给该进程,若资源充足,则计算将这些资源分配给进程后,是否会让系统处于不安全状态。如果不会才将资源进行分配,否则让进程等待。

银行家算法的代码实现:

#include <iostream>
#define maxP 10
#define maxS 10
using namespace std;
int Available[maxS];
int Max[maxP][maxS];
int Allocation[maxP][maxS];
int Need[maxP][maxS];
int Request[maxS];
int Finish[maxP];
int path[maxP] = { 0 };
int PNum, RNum;
void outPath() {
    cout << "系统安全序列是:\n";
    cout << "P" << path[0] - 1;
    for (int i = 1; path[i] != 0; i++) {
        cout << "->P" << path[i] - 1;
    }
    for (int i = 0; i < PNum; i++) path[i] = 0;
    cout << endl;
}
int BankSafe() {
    int i, j, l = 0;
    int Work[maxS];
    for (i = 0; i < RNum; i++) Work[i] = Available[i];
    for (i = 0; i < PNum; i++) Finish[i] = 0;
    for (i = 0; i < PNum; i++) {
        if (Finish[i] == 1)
            continue;
        else {
            for (j = 0; j < RNum; j++) {
                if (Need[i][j] > Work[j])
                    break;
            }
            if (j == RNum) {
                Finish[i] = 1;
                for (int k = 0; k < RNum; k++)
                    Work[k] += Allocation[i][k];
                path[l++] = i + 1;
                i = -1;
            }
            else continue;
        }
        if (l == PNum) {
            return 1;
        }
    }
    return 0;
}
void input(int PNum, int RNum) {
    cout << "输入每个进程最多所需的各类资源数:\n";
    for (int i = 0; i < PNum; i++) {
        cout << "P" << i << " : ";
        for (int j = 0; j < RNum; j++)
            cin >> Max[i][j];
    }
    cout << "输入每个进程已经分配的各类资源数:\n";
    for (int i = 0; i < PNum; i++) {
        cout << "P" << i << " : ";
        for (int j = 0; j < RNum; j++) {
            cin >> Allocation[i][j];
            Need[i][j] = Max[i][j] - Allocation[i][j];
            if (Need[i][j] < 0) {
                cout << "你输入的进程P" << i << "所拥有的第" << j + 1 << "个资源错误,请重新输入:\n";
                j--;
                continue;
            }
        }
    }
    cout << "请输入各个资源现有的数目:\n";
    for (int i = 0; i < RNum; i++)
        cin >> Available[i];
}
int requestP() {
    int Pi;
    cout << "输入要申请资源的进程号(0-4):";
    cin >> Pi;
    Pi;
    cout << "输入进程所请求的各资源的数量:";
    for (int i = 0; i < RNum; i++)
        cin >> Request[i];
    for (int i = 0; i < RNum; i++) {
        if (Request[i] > Need[Pi][i]) {
            cout << "所请求资源数超过进程的需求量!\n";
            return 1;
        }
        if (Request[i] > Available[i]) {
            cout << "所请求资源数超过系统所有的资源数!\n";
            return 1;
        }
    }
    for (int i = 0; i < RNum; i++) {
        Available[i] -= Request[i];
        Allocation[Pi][i] += Request[i];
        Need[Pi][i] -= Request[i];
    }
    if (BankSafe()) {
        cout << "系统安全!\n";
        outPath();
        cout << "同意分配请求!\n";
    }
    else {
        for (int i = 0; i < RNum; i++) {
            Available[i] += Request[i];
            Allocation[Pi][i] -= Request[i];
            Need[Pi][i] += Request[i];
        }
        cout << "请求后,系统不安全,你的请求被拒!\n";
    }
    return 0;
}
void outDATA() {
    int i, j;
    cout << "\n系统可用的资源数为 :";
    for (j = 0; j < RNum; j++)
        cout << " " << Available[j];
    cout << endl << "各进程还需要的资源量:" << endl;
    for (i = 0; i < PNum; i++) {
        cout << "进程 P" << i << " :";
        for (j = 0; j < RNum; j++)
            cout << " " << Need[i][j];
        cout << endl;
    }
    cout << endl << "各进程已经得到的资源量:" << endl;
    for (i = 0; i < PNum; i++) {
        cout << "进程 P" << i << " :";
        for (j = 0; j < RNum; j++)
            cout << " " << Allocation[i][j];
        cout << endl;
    }
    cout << endl;
}
int main() {
    cout << "输入进程的数目:";
    cin >> PNum;
    cout << "输入资源的种类:";
    cin >> RNum;
    input(PNum, RNum);
    if (BankSafe()) {
        cout << "当前系统安全!\n";
        outPath();
    }
    else {
        cout << "当前系统不安全!\n";
        return 0;
    }
    while (1) {
        requestP();
        outDATA();
        char chose;
        cout << "是否再次请求分配?是请按Y/y,否请按N/n:\n";
        while (1) {
            cin >> chose;
            if (chose == 'Y' || chose == 'y' || chose == 'N' || chose == 'n')
                break;
            else {
                cout << "请按要求重新输入:\n";
                continue;
            }
        }
        if (chose == 'Y' || chose == 'y')
            continue;
        else break;
    }
    return 0;
}

采用银行家算法来避免死锁是非常可靠的,同时也是非常保守的,因为它限制了进程对资源的存取,从而降低了并发运行的程度。

四:死锁的检测(死锁检测算法)

死锁检测算法的思想

不再预防或者避免死锁,而是允许进入死锁状态,定时调用死锁检测算法,发现死锁则采用死锁恢复机制。


http://www.niftyadmin.cn/n/1580514.html

相关文章

Linux系统编程:生产者与消费者模型

前言 生产者和消费者问题是线程模型中的经典问题&#xff1a;生产者和消费者在同一时间段内共用同一个存储空间&#xff0c;生产者往存储空间中添加资源&#xff0c;消费者从存储空间中取走资源&#xff0c;当存储空间为空时&#xff0c;消费者阻塞&#xff0c;当存储空间满时…

Ext学习笔记05 - UI组件 - Panel,TextField

TextField TextField在Ext.form.TextField包下面&#xff08;叫包叫习惯了&#xff09;&#xff0c;是form组件中的一个&#xff0c;是对传统文本框的封装&#xff08;input&#xff09;。 在页面中直接使用某些Component是不起作用的&#xff0c;因为Ext UI设计是类似Swing布局…

C/C++中的关键字:extern的用法解析

前言 在C/C中存在许许多多的关键字&#xff0c;它们的用法和功能都互不相同&#xff0c;今天我们来主要讨论一下extern这个关键字的用法。 在C/C中&#xff0c;extern关键字可以用于变量或者函数的声明前&#xff0c;还可以用于进行链接的指定。 一&#xff1a;extern 用于变…

.NET 4

首先提供两篇值得推荐的博文&#xff1a;http://blog.csdn.net/bitfan/archive/2011/01/18/6149746.aspx 在我们之前的开发中&#xff0c;对于ajax程序&#xff0c;都是通过jQuery调用标记为【System.Web.Script.Services.ScriptService】的WebService&#xff0c;然后在W…

编程思想:面向对象和面向过程的区别与联系

前言 何谓面向对象&#xff1f;何谓面向过程&#xff1f;对于这编程界的两大思想&#xff0c;一直贯穿在我们学习和工作当中。我们知道面向过程和面向对象&#xff0c;但要让我们讲出来个所以然&#xff0c;又感觉是不知从何说起。而这种茫然&#xff0c;其实就是对这两大编程…

超级简单,三种方法制作WinPE系统维护U盘

http://www.iteeyan.com/2010/08/simple-make-winpe-disk/转载于:https://www.cnblogs.com/qiantuwuliang/archive/2011/01/22/1941883.html

C++中引用类型的简单剖析

前言 对于习惯使用C语言进行开发的同学们&#xff0c;在看到C中出现的&符号&#xff0c;可能会陷入误区&#xff0c;因为在C语言中&符号表示了取地址符&#xff0c;但其实&在C中却有着不同的意义与用途——引用。 一&#xff1a;引用的简介 1.1 引用概念 引用就…

h3c交换机配置(下)

六、以太网安全技术&#xff08;一&#xff09; 以太网ACL控制1、ACL匹配原则&#xff08;1&#xff09;支持两种匹配顺序配置顺序&#xff1a;根据配置规则的先后顺序进行规则匹配自动排序&#xff1a;根据“深度优先”的顺序进行规则匹配。即越详细的越最先匹配。&#xff08…