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

前言

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

一:死锁的产生

死锁产生的四个必要条件

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;
}

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

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

死锁检测算法的思想

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

  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值