银行家算法

银行家算法(Banker’s Algorithm)是一个避免死锁(Deadlock)的著名算法,是由艾兹格·迪杰斯特拉在1965年为T.H.E系统设计的一种避免死锁产生的算法。它以银行借贷系统的分配策略为基础,判断并保证系统的安全运行。

gitee地址

算法分析

通过文件读取输入数组数据,然后根据键盘输入执行分配处理,再执行安全算法,若安全算法通过,则分配成功,否则分配失败。

全局变量

// 进程数
#define N 5
// 资源数
#define M 3
// 可利用资源数组
int Available[M];
// 最大资源数组
int Max[N][M];
// 已经分配资源数组
int Allocation[N][M];
// 需求数组
int Need[N][M];
// 是否完成
int Success[N];

读取文件函数

read1_data:从fileName文件中读取m个数字到arr中。

read2_data:从fileName文件中读取n行,每行m个数字到arr中。

/**
 * 读取一维数组
*/
void read1_data(char *fileName, int arr[], int m)
{
    int i;
    FILE *fp = fopen(fileName, "rb");
    for (i = 0; i < m; i++)
    {
        fscanf(fp, "%d", &arr[i]);
    }
}

/**
 * 读取二维数组
*/
void read2_data(char *fileName, int arr[][M], int n, int m)
{
    int i;
    int j;
    FILE *fp = fopen(fileName, "rb");
    for (i = 0; i < n; i++)
    {
        for (j = 0; j < m; j++)
        {
            fscanf(fp, "%d", &arr[i][j]);
        }
    }
}

处理函数

current表示待处理的线程id,request是该线程的请求资源数组。

void handle(int current, int request[])
{
    // 进程任务是否完成
    int finish = 1;
    for (int i = 0; i < M; i++)
    {
        if (request[i] > Need[current][i])
        {
            printf("请求的资源大于需要的资源\n");
            return;
        }
        if (request[i] > Available[i])
        {
            printf("没有足够的资源可分配\n");
            return;
        }
    }
    for (int i = 0; i < M; i++)
    {
        Available[i] -= request[i];
        Allocation[current][i] += request[i];
        Need[current][i] -= request[i];
    }
    // 安全检查
    if (!check_secure())
    {
        //如果检查不通过 回撤改变
        for (int i = 0; i < M; i++)
        {
            Available[i] += request[i];
            Allocation[current][i] -= request[i];
            Need[current][i] += request[i];
        }
        printf("安全检查未通过\n");
        return;
    }
    for (int i = 0; i < M; i++)
    {
        if (Need[current][i] > 0)
        {
            finish = 0;
            break;
        }
    }
    // 如果进程need都为0表示进程完成,回收资源
    if (finish)
    {
        for (int i = 0; i < M; i++)
        {
            Available[i] += Allocation[current][i];
        }
        Success[current] = 1;
    }
}

安全检查

定义work数组和finish数组。
将work数组初始化等于Available数组,finish数组全部置0表示未完成。

当分配了资源后的cur线程Need[cur]每个元素都小于work,则这个线程可以完成,并将其Need[cur]添加到work里,置finish[cur] = 1。
如果最后finish都为1,表示系统安全。否则不安全。

当系统安全时,finish都为1,以及系统不安全的时候,finish不全为1,但是finish数组已经不会再改变了。如果判断其finish数组不会改变了?

定义一个中间变量flag,如果从第一个线程到最后一个线程中,有线程完成,则flag+1。如果最后循环一轮,flag还是等于0,表示此时finish数组不会再改变了。退出循环,判断系统是否安全。

/**
 * 安全检查
*/
int check_secure()
{
    // 工作向量
    int work[M];
    // 完成向量
    int finish[N];
    // work一开始等于Available, finish全部置0
    for (int i = 0; i < M; i++)
    {
        work[i] = Available[i];
    }
    for (int i = 0; i < N; i++)
    {
        finish[i] = 0;
    }
    printf("安全序列: ");
    while (1)
    {
        // 标识这一轮是否有进程完成
        int flag = 0;
        for (int i = 0; i < N; i++)
        {
            // 如果这个进程没有完成,则判断其是否可以完成
            if (!finish[i])
            {
                // temp=0表示可以完成
                int temp = 0;
                for (int j = 0; j < M; j++)
                {
                    if (Need[i][j] > work[j])
                    {
                        temp = 1;
                        break;
                    }
                }
                if (!temp)
                {
                    for (int j = 0; j < M; j++)
                    {
                        work[j] += Allocation[i][j];
                    }
                    finish[i] = 1;
                    flag++;
                    printf("%d ", i);
                }
            }
        }
        if (!flag)
        {
            break;
        }
    }
    printf("\n");
    for (int i = 0; i < N; i++)
    {
        if (!finish[i])
        {
            // 有不能完成的则为不安全
            return 0;
        }
    }
    // 安全返回1
    return 1;
}
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐