操作系统-预防进程死锁的银行家算法-详细设计附源码一、需求

一、需求分析

1、程序设计的任务和目的

通过这次实验,加深对进程死锁的理解,进一步掌握进程资源的分配、死锁的检测和安全序列的生成方法。

2、输入的形式和输入值的范围

进程个数n,资源种类m,T0时刻各个进程的资源分配情况(可以运行输入,也可以在程序中设置)

3、输出的形式

如果安全,输出安全的进程序列,不安全则提示信息。

4、程序所能达到的功能

程序模拟预防进程死锁的银行家算法的工作过程。假设系统中有n个进程P1, … ,Pn,有m类可分配的资源R1, … ,Rm,在T0时刻,进程Pi分配到的j类资源为Allocationij个,它还需要j类资源Need ij个,系统目前剩余j类资源Workj个,现采用银行家算法进行进程资源分配预防死锁的发生。

5、测试数据,包括正确的输入及其输出结果和含有错误的输入及其输出结果

正确用例

输入

请输入进程个数n:5
请输入资源种类m:3
请输入进程1的资源1的最大允许数量Max[1]:7
请输入进程1的资源2的最大允许数量Max[2]:5
请输入进程1的资源3的最大允许数量Max[3]:3
请输入进程1的资源1的已分配数量Allocation[1]:0
请输入进程1的资源2的已分配数量Allocation[2]:1
请输入进程1的资源3的已分配数量Allocation[3]:0
请输入进程2的资源1的最大允许数量Max[1]:3
请输入进程2的资源2的最大允许数量Max[2]:2
请输入进程2的资源3的最大允许数量Max[3]:2
请输入进程2的资源1的已分配数量Allocation[1]:2
请输入进程2的资源2的已分配数量Allocation[2]:0
请输入进程2的资源3的已分配数量Allocation[3]:0
请输入进程3的资源1的最大允许数量Max[1]:9
请输入进程3的资源2的最大允许数量Max[2]:0
请输入进程3的资源3的最大允许数量Max[3]:2
请输入进程3的资源1的已分配数量Allocation[1]:3
请输入进程3的资源2的已分配数量Allocation[2]:0
请输入进程3的资源3的已分配数量Allocation[3]:2
请输入进程4的资源1的最大允许数量Max[1]:2
请输入进程4的资源2的最大允许数量Max[2]:2
请输入进程4的资源3的最大允许数量Max[3]:2
请输入进程4的资源1的已分配数量Allocation[1]:2
请输入进程4的资源2的已分配数量Allocation[2]:1
请输入进程4的资源3的已分配数量Allocation[3]:1
请输入进程5的资源1的最大允许数量Max[1]:4
请输入进程5的资源2的最大允许数量Max[2]:3
请输入进程5的资源3的最大允许数量Max[3]:3
请输入进程5的资源1的已分配数量Allocation[1]:0
请输入进程5的资源2的已分配数量Allocation[2]:0
请输入进程5的资源3的已分配数量Allocation[3]:2
请输入可用资源1的可用数量:3
请输入可用资源2的可用数量:3
请输入可用资源3的可用数量:2
复制代码

输出

SafeOrder为:      进程   2      进程   4      进程   5      进程   1      进程   3

剩余资源情况为:
资源 1剩余数量: 3
资源 2剩余数量: 3
资源 3剩余数量: 2

是否还有新请求,若有请输入进程序号,若无请输入0:2
请输入进程2需求的资源1的数量:1
请输入进程2需求的资源2的数量:0
请输入进程2需求的资源3的数量:2
SafeOrder为:      进程   2      进程   4      进程   5      进程   1      进程   3

剩余资源情况为:
资源 1剩余数量: 2
资源 2剩余数量: 3
资源 3剩余数量: 0
复制代码

错误用例(输入负值,影响正确结果)

输入

请输入进程个数n:1
请输入资源种类m:3
请输入进程1的资源1的最大允许数量Max[1]:1
请输入进程1的资源2的最大允许数量Max[2]:1
请输入进程1的资源3的最大允许数量Max[3]:1
请输入进程1的资源1的已分配数量Allocation[1]:-1
请输入进程1的资源2的已分配数量Allocation[2]:-1
请输入进程1的资源3的已分配数量Allocation[3]:-1
请输入可用资源1的可用数量:2
请输入可用资源2的可用数量:2
请输入可用资源3的可用数量:2
复制代码

输出

SafeOrder为:      进程   1

剩余资源情况为:
资源 1剩余数量: 2
资源 2剩余数量: 2
资源 3剩余数量: 2

是否还有新请求,若有请输入进程序号,若无请输入0:1
请输入进程1需求的资源1的数量:2
请输入进程1需求的资源2的数量:2
请输入进程1需求的资源3的数量:2
SafeOrder为:      进程   1

剩余资源情况为:
资源 1剩余数量: 0
资源 2剩余数量: 0
资源 3剩余数量: 0
复制代码

二、概要设计

1、抽象数据类型的定义

int n;//进程个数n
int m;//资源种类m
int Available[MaxNumber];//可用资源数量
int Request[MaxNumber];//进程请求的资源数量
int SafeOrder[MaxNumber];//安全进程序列

//定义进程的数据结构
typedef struct {
    int Max[MaxNumber];
    int Allocation[MaxNumber];
    int Need[MaxNumber];
    bool Finished;//完成状态
} Progress;
复制代码

2、主程序的流程

int main() {
    BankerAlgorithm bankerAlgorithm{};
    bankerAlgorithm.Input();
    bankerAlgorithm.Order(bankerAlgorithm.progress, bankerAlgorithm.Available);

    return 0;
}
复制代码

3、各程序模块之间的层次(调用)关系

int main() {
    BankerAlgorithm bankerAlgorithm{};
    bankerAlgorithm.Input();
    bankerAlgorithm.Order(bankerAlgorithm.progress, bankerAlgorithm.Available);

    return 0;
}

//输入函数调用InputAlgorithm函数选择输入函数
void Input() {
    ···
}

//进行安全进程检测并输出安全序列
void Order(Progress pg[MaxNumber], int a[MaxNumber]) {
    //定义下标数
    int orderNum = 0;

    //复制进程操作
    Progress progressCopy[MaxNumber];
    for (int i = 1; i <= n; i++) {
        progressCopy[i] = pg[i];
    }

    //复制可用需求数
    int available[MaxNumber];
    for (int i = 1; i <= m; i++) {
        available[i] = a[i];
    }

    //调用NewFinish函数判断所有进程是否完成
    while (!NewFinish(progressCopy)) {
        //调用IsSafe函数判断现在是否安全
        if (IsSafe(progressCopy, available)) {
            for (int i = 1; i <= n; i++) {
                if (!progressCopy[i].Finished &&
                    //调用IsExecutable函数判断可分配资源可否满足该进程
                    IsExecutable(progressCopy[i], available)) {
                    //只有同时满足进程未完成、可分配需求足够才进行分配
    				···
                }
            }
        } else {
            cout << "不安全" << endl;
            exit(0);
        }
    }

    //输出SafeOrder
    ···

    NewRequest(pg, a);
}

//判断是否有新请求,若无则退出,若有则输入其请求资源数
void NewRequest(Progress pg[MaxNumber], int a[MaxNumber]) {
    ···
        
    //输出剩余资源数量参考
    ···

    //判断新请求,若有可用新请求,调用Order函数重新进行银行家算法安全计算
    cout << endl << "是否还有新请求,若有请输入进程序号,若无请输入0:";
    cin >> newRequest;
    if (newRequest != 0) {
        for (int i = 1; i <= m; i++) {
			//若可分配资源不足或超出需求,则重新调用NewRequest函数
            NewRequest(pg, a);
        }
    	···
        Order(pg, a);
    } else {
        return;
    }
}

//判断所有进程是否完成
bool NewFinish(Progress pg[MaxNumber]) {
    ···
}

//判断可分配资源可否满足该进程
bool IsExecutable(Progress pg, const int a[MaxNumber]) {
    ···
}

//判断现在是否安全
bool IsSafe(Progress pg[MaxNumber], int a[MaxNumber]) {
    ···
}
复制代码

三、详细设计

实现程序模块的具体算法

1、Order银行家算法排序

//进行安全进程检测并输出安全序列
void Order(Progress pg[MaxNumber], int a[MaxNumber]) {
    //定义下标数
    int orderNum = 0;

    //复制进程操作
    ···

    //复制可用需求数
    ···

    //调用NewFinish函数判断所有进程是否完成
    while (!NewFinish(progressCopy)) {
        //调用IsSafe函数判断现在是否安全
        if (IsSafe(progressCopy, available)) {
            for (int i = 1; i <= n; i++) {
                if (!progressCopy[i].Finished &&
                    //调用IsExecutable函数判断可分配资源可否满足该进程
                    IsExecutable(progressCopy[i], available)) {
                    //只有同时满足进程未完成、可分配需求足够才进行分配
    				···
                }
            }
        } else {
            cout << "不安全" << endl;
            exit(0);
        }
    }

    //输出SafeOrder
    ···
    //若为安全状态,重新调用NewRequest函数请求下一个需求输入
    NewRequest(pg, a);
}
复制代码

2、NewRequest发起新请求

//判断是否有新请求,若无则退出,若有则输入其请求资源数
void NewRequest(Progress pg[MaxNumber], int a[MaxNumber]) {
    ···
        
    //输出剩余资源数量参考
    ···

    //判断新请求,若有可用新请求,调用Order函数重新进行银行家算法安全计算
    cout << endl << "是否还有新请求,若有请输入进程序号,若无请输入0:";
    cin >> newRequest;
    if (newRequest != 0) {
        for (int i = 1; i <= m; i++) {
			//若可分配资源不足或超出需求,则重新调用NewRequest函数
            NewRequest(pg, a);
        }
    	···
        Order(pg, a);
    } else {
        return;
    }
}
复制代码

3、NewFinish函数判断进程完成

//判断所有进程是否完成
bool NewFinish(Progress pg[MaxNumber]) {
    bool finished = true;
    for (int i = 1; i <= n; i++) {
        finished *= pg[i].Finished;
    }
    return finished;
}
复制代码

4、IsExecutable函数判断资源充足与否

//判断可分配资源可否满足该进程
bool IsExecutable(Progress pg, const int a[MaxNumber]) {
    bool isExecutable = true;
    for (int i = 1; i <= m; i++) {
        isExecutable *= (pg.Need[i] <= a[i]);
    }
    return isExecutable;
}
复制代码

5、IsSafe函数判断当前进程是否安全

//判断现在是否安全
bool IsSafe(Progress pg[MaxNumber], int a[MaxNumber]) {
    bool isExecutable = false;
    for (int i = 1; i <= n; i++) {
        if (IsExecutable(pg[i], a)) {
            isExecutable = true;
            return isExecutable;
        }
    }
    return isExecutable;
}
复制代码

四、调试分析

调试过程中遇到的问题以及解决方法,设计与实现的回顾讨论和分析

算法的性能分析(包括基本操作和其它算法的时间复杂度和空间复杂度的分析)及其改进设想

性能分析

算法 时间复杂度 空间复杂度
Order算法安全进程检测 T(n) = O(n2) S(n) = O(n)
NewRequest算法请求资源 T(n) = O(n2) S(n) = O(n2)
NewFinish算法判断所有进程是否完成 T(n) = O(n) S(n) = O(n)
IsExecutable算法判断可分配资源可否满足该进程 T(n) = O(n) S(n) = O(n)
IsSafe算法判断进程是否处于安全状态 T(n) = O(n) S(n) = O(n)

改进设想

输出较为繁复,多次测试较为不便,可改为读取文件输入

五、用户使用说明

使用说明

  • 控制台会提示要求用户进行输入,按提示输入内容即可
  • 不要输入负值,将影响正确结果
  • 选择算法输入完成后将会输出安全的进程序列
  • 可根据需要选择是否使用进行其他资源请求或退出

六、测试结果

测试结果,包括输入和输出

D:\Documents\MyCourse\OperatingSystem\cmake-build-debug\chapter03.exe
请输入进程个数n:5
请输入资源种类m:3
请输入进程1的资源1的最大允许数量Max[1]:7
请输入进程1的资源2的最大允许数量Max[2]:5
请输入进程1的资源3的最大允许数量Max[3]:3
请输入进程1的资源1的已分配数量Allocation[1]:0
请输入进程1的资源2的已分配数量Allocation[2]:1
请输入进程1的资源3的已分配数量Allocation[3]:0
请输入进程2的资源1的最大允许数量Max[1]:3
请输入进程2的资源2的最大允许数量Max[2]:2
请输入进程2的资源3的最大允许数量Max[3]:2
请输入进程2的资源1的已分配数量Allocation[1]:2
请输入进程2的资源2的已分配数量Allocation[2]:0
请输入进程2的资源3的已分配数量Allocation[3]:0
请输入进程3的资源1的最大允许数量Max[1]:9
请输入进程3的资源2的最大允许数量Max[2]:0
请输入进程3的资源3的最大允许数量Max[3]:2
请输入进程3的资源1的已分配数量Allocation[1]:3
请输入进程3的资源2的已分配数量Allocation[2]:0
请输入进程3的资源3的已分配数量Allocation[3]:2
请输入进程4的资源1的最大允许数量Max[1]:2
请输入进程4的资源2的最大允许数量Max[2]:2
请输入进程4的资源3的最大允许数量Max[3]:2
请输入进程4的资源1的已分配数量Allocation[1]:2
请输入进程4的资源2的已分配数量Allocation[2]:1
请输入进程4的资源3的已分配数量Allocation[3]:1
请输入进程5的资源1的最大允许数量Max[1]:4
请输入进程5的资源2的最大允许数量Max[2]:3
请输入进程5的资源3的最大允许数量Max[3]:3
请输入进程5的资源1的已分配数量Allocation[1]:0
请输入进程5的资源2的已分配数量Allocation[2]:0
请输入进程5的资源3的已分配数量Allocation[3]:2
请输入可用资源1的可用数量:3
请输入可用资源2的可用数量:3
请输入可用资源3的可用数量:2

SafeOrder为:      进程   2      进程   4      进程   5      进程   1      进程   3

剩余资源情况为:
资源 1剩余数量: 3
资源 2剩余数量: 3
资源 3剩余数量: 2

是否还有新请求,若有请输入进程序号,若无请输入0:2
请输入进程2需求的资源1的数量:1
请输入进程2需求的资源2的数量:0
请输入进程2需求的资源3的数量:2
SafeOrder为:      进程   2      进程   4      进程   5      进程   1      进程   3

剩余资源情况为:
资源 1剩余数量: 2
资源 2剩余数量: 3
资源 3剩余数量: 0

是否还有新请求,若有请输入进程序号,若无请输入0:4
请输入进程4需求的资源1的数量:1
超出需求,请重新输入


剩余资源情况为:
资源 1剩余数量: 2
资源 2剩余数量: 3
资源 3剩余数量: 0

是否还有新请求,若有请输入进程序号,若无请输入0:5
请输入进程5需求的资源1的数量:1
请输入进程5需求的资源2的数量:3
请输入进程5需求的资源3的数量:0
不安全

Process finished with exit code 0
复制代码

七、附录

带注释的源程序

#include <iostream>
#include <iomanip>

using namespace std;
#define MaxNumber 100

class BankerAlgorithm {
public:

    int n;//进程个数n
    int m;//资源种类m
    int Available[MaxNumber];//可用资源数量
    int Request[MaxNumber];//进程请求的资源数量
    int SafeOrder[MaxNumber];//安全进程序列

    //定义进程的数据结构
    typedef struct {
        int Max[MaxNumber];
        int Allocation[MaxNumber];
        int Need[MaxNumber];
        bool Finished;//完成状态
    } Progress;

    Progress progress[MaxNumber];

    //输入进程数、资源种类、各进程有关资源的Max、Allocation、Need数量
    void Input() {
        cout << "请输入进程个数n:";
        cin >> n;
        cout << "请输入资源种类m:";
        cin >> m;
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                cout << "请输入进程" << i << "的资源" << j << "的最大允许数量Max[" << j << "]:";
                cin >> progress[i].Max[j];
            }
            for (int j = 1; j <= m; j++) {
                cout << "请输入进程" << i << "的资源" << j << "的已分配数量Allocation[" << j << "]:";
                cin >> progress[i].Allocation[j];
            }
            for (int j = 1; j <= m; j++) {
                progress[i].Need[j] = progress[i].Max[j] - progress[i].Allocation[j];
            }
        }

        for (int i = 1; i <= m; i++) {
            cout << "请输入可用资源" << i << "的可用数量:";
            cin >> Available[i];
        }

        cout << endl;
    }

    //判断是否有新请求,若无则退出,若有则输入其请求资源数
    void NewRequest(Progress pg[MaxNumber], int a[MaxNumber]) {
        int newRequest;

        //剩余资源数量参考
        cout << endl << endl << "剩余资源情况为:" << endl;
        for (int i = 1; i <= m; i++) {
            cout << setw(6) << "资源" << setw(2) << i << setw(6) << "剩余数量:" << setw(2) << a[i] << endl;
        }

        //判断新请求
        cout << endl << "是否还有新请求,若有请输入进程序号,若无请输入0:";
        cin >> newRequest;
        if (newRequest != 0) {
            for (int i = 1; i <= m; i++) {
                cout << "请输入进程" << newRequest << "需求的资源" << i << "的数量:";
                cin >> Request[i];
                if (Request[i] > a[i]) {
                    cout << "可分配资源不足,请重新输入" << endl;
                    NewRequest(pg, a);
                }
                if (Request[i] > pg[newRequest].Need[i]) {
                    cout << "超出需求,请重新输入" << endl;
                    NewRequest(pg, a);
                }
            }

            for (int i = 1; i <= m; i++) {
                a[i] -= Request[i];
                pg[newRequest].Allocation[i] += Request[i];
                pg[newRequest].Need[i] -= Request[i];
            }
            Order(pg, a);
        } else {
            return;
        }
    }

    void Order(Progress pg[MaxNumber], int a[MaxNumber]) {
        //定义下标数
        int orderNum = 0;

        //复制进程操作
        Progress progressCopy[MaxNumber];
        for (int i = 1; i <= n; i++) {
            progressCopy[i] = pg[i];
        }

        //复制可用需求数
        int available[MaxNumber];
        for (int i = 1; i <= m; i++) {
            available[i] = a[i];
        }

        while (!NewFinish(progressCopy)) {//若有
            if (IsSafe(progressCopy, available)) {
                for (int i = 1; i <= n; i++) {
                    if (!progressCopy[i].Finished &&
                        IsExecutable(progressCopy[i], available)) {//只有同时满足进程未完成、可分配需求足够才进行分配
                        progressCopy[i].Finished = true;
                        for (int j = 1; j <= m; j++) {
                            available[j] += progressCopy[i].Allocation[j];
                        }
                        SafeOrder[++orderNum] = i;
                    }
                }
            } else {
                cout << "不安全" << endl;
                exit(0);
            }
        }

        //输出SafeOrder
        cout << "SafeOrder为:";
        for (int i = 1; i <= n; i++) {
            cout << setw(12) << "进程" << setw(4) << SafeOrder[i];
        }

        NewRequest(pg, a);
    }

    //判断所有进程是否完成
    bool NewFinish(Progress pg[MaxNumber]) {
        bool finished = true;
        for (int i = 1; i <= n; i++) {
            finished *= pg[i].Finished;
        }
        return finished;
    }

    //判断可分配资源可否满足该进程
    bool IsExecutable(Progress pg, const int a[MaxNumber]) {
        bool isExecutable = true;
        for (int i = 1; i <= m; i++) {
            isExecutable *= (pg.Need[i] <= a[i]);
        }
        return isExecutable;
    }

    //判断现在是否安全
    bool IsSafe(Progress pg[MaxNumber], int a[MaxNumber]) {
        bool isExecutable = false;
        for (int i = 1; i <= n; i++) {
            if (IsExecutable(pg[i], a)) {
                isExecutable = true;
                return isExecutable;
            }
        }
        return isExecutable;
    }
};

int main() {
    BankerAlgorithm bankerAlgorithm{};
    bankerAlgorithm.Input();
    bankerAlgorithm.Order(bankerAlgorithm.progress, bankerAlgorithm.Available);

    return 0;
}
复制代码