Deadlock Avoidance Using Banker Algorithm

In the operating system, the banker algorithm is an important algorithm to avoid deadlocks.
This paper addresses the question on page p123 of Computer Operating System (Fourth Edition) (Tang Xiaodan): ** If the request vector from P0 is changed to Request0(0,1,0) in the banker's algorithm, the reader should consider whether the system can allocate resources to it. ** Make a simulation.
This topic has three resources A,B,C., and five processes P 0~P 4.
1. Data structure in banker's algorithm
1) Available resource Available is an array of three elements representing the amount of Available resources of ABC.
2) Maximum demand matrix Max, which is a 53 matrix.
3) Assign matrix A to location, which is a 53 matrix.
4) Need, a 5*3 matrix.
Where Need[i,j] = Max[i,j]-Allocation[i,j]
5) End array finish, a bool-type array of length 5, to mark whether the five processes, P 0~P 4, are executed sequentially.
For a detailed description of this problem, see the corresponding location in the textbook.
Next, code will simulate the problem solving process.

/*
The banker's algorithm simulates an example on page 122, simulated from time T0
*/
#include <iostream>
#include <stack>
using namespace std;
typedef struct Bank{
    int Available[3] = {2,3,0};  //Total number of resources
    int Max[5][3] = {7,5,3,
                    3,2,2,
                    9,0,2,
                    2,2,2,
                    4,3,3};//How much resources are needed
    int Allocation[5][3] = {0,1,0,
                    3,0,2,
                    3,0,2,
                    2,1,1,
                    0,0,2};    //Number of resources allocated
    int Need[5][3];           //How much more resources are needed
    bool finish[5] = {false,false,false,false,false};   //Completion Mark
}Bank;
void Change_Need_Matrix(Bank* bank){
    for(int i=0;i<5;i++){
        for(int j=0;j<3;j++){
            bank->Need[i][j] = bank->Max[i][j] - bank->Allocation[i][j];
        }
    }
}//Need matrix is derived from Max and Alocation matrices. Need = Max-Allocation;
Bank* Copy_Bank(Bank* Original_bank){
    Bank* Copy = new Bank();
    for(int i = 0;i<3;i++){
        Copy->Available[i] = Original_bank->Available[i];
    }
    for(int i = 0;i<5;i++){
        for(int j = 0;j<3;j++){
            Copy->Max[i][j] = Original_bank->Max[i][j];
            Copy->Allocation[i][j] = Original_bank->Allocation[i][j];
            Copy->Need[i][j] = Original_bank->Need[i][j];
        }
    }
    for(int i=0;i<5;i++){
        Copy->finish[i] = Original_bank->finish[i];
    }
    return Copy;
}//Return a copy of the current live bank. For security checks, you can't do security checks on the origin, which destroys the site, so you make a copy and do security checks on this copy.
bool Judge_Simulation_End(Bank* bank){
    for(int i=0;i<5;i++){
        if(bank->finish[i] == false){
            return false;
        }
    }
    return true;
}    //If the finish es of all five processes are true, they can end.
bool Judge_Process_Finish(int Process_id,Bank* bank){
    for(int i=0;i<3;i++){
        if(bank->Need[Process_id][i] != 0 ){
            return false;
        }
    }
    return true;
}  //To determine if a process has finished running, set the finishes of the process to true.
bool Judge_Add_To_Stack(int* request,int* Available){
    for(int i=0;i<3;i++){
        if(request[i]>Available[i]){
            return false;
        }
    }
    return true;
}  //Determine whether to add to the process id stack and the field stack.
bool Judge_Safe(int id,int* request,Bank* bank){
    /*
    This function simulates a request and determines if it is secure
    id-->id number of the process, int type, 0-4
    request-->A three-dimensional int array that records the amount of A, B, and C resources requested by the process id, respectively.
    bank-->Theme Live, Copy Template
    */
    Bank* temporary_bank = Copy_Bank(bank);   //Make a copy of the original live bank temporary_bank.
    for(int i=0;i<3;i++){
        temporary_bank->Need[id][i] -= request[i];
        temporary_bank->Allocation[id][i] += request[i];
        temporary_bank->Available[i] -= request[i];
    }    //Tempy_on-site at copy Execute this request on the bank.
    if(Judge_Process_Finish(id,temporary_bank) == true){
        temporary_bank->finish[id] = true;
        for(int i=0;i<3;i++){
            temporary_bank->Available[i] += temporary_bank->Allocation[id][i];
        }
    }    //If the id process ends after the request is executed, return its Allocation to Available.
    if(Judge_Simulation_End(temporary_bank)==true){
        cout<<"Resource allocation complete!"<<endl;
        exit(0);   //The resource allocation is complete and the program exits directly.
    }    //If all five processes are finish ed, resource allocation is complete
    //The purpose of the security check is to find out if a sequence can be found after the current request has been executed, so that each process can allocate resources in this order for execution, and all can be successfully completed.
    //Note: It is safe to find only one sequence of allocated resources that will succeed, but there may be many sequences of allocated resources that need not be all found.
    //Finding a sequence of successful resource allocations requires two stacks, a process id stack, and a stack that records the site. Two stacks are synchronized on and off the stack.
    stack <int>process_id_stack;    //Process id stack.
    stack <Bank*>scene;             //Record the stack of the site. This scene, in fact, refers to the current temporary_bank.
    for(int i=0;i<5;i++){
        if((temporary_bank->finish[i] == false)&&(Judge_Add_To_Stack(temporary_bank->Need[i],temporary_bank->Available) == true)){
                process_id_stack.push(i);
                scene.push(temporary_bank);
        }
    }//Judge_ Add_ To_ The Stack function determines whether each process can be stacked based on Need for each process and Available for that time.
    while(!process_id_stack.empty()){
        if(Judge_Simulation_End(temporary_bank) == true){
            return true;   //During the simulation, the process can all end and be safely scheduled
        }
        else{
            int top = process_id_stack.top();  //Takes the top element of the stack, the reason why the top element can be put on the stack indicates that it can be allocated to all its Need resources at this time.
            for(int i=0;i<3;i++){
                temporary_bank->Available[i] -= temporary_bank->Need[top][i];
                temporary_bank->Allocation[top][i] += temporary_bank->Need[top][i];
                temporary_bank->Need[top][i] = 0;
                temporary_bank->Available[i] += temporary_bank->Allocation[top][i];
            }     //Then assign it all the Need resources it needs!
            temporary_bank->finish[top] = true;   //After allocation, Need is reduced to zero, and the process has ended in this way of allocation.
                                                  //But we haven't yet decided if this is a security check.
            int miss = 0;        //Used to record whether the next round of P 0-P 5 can be stacked or not, +1.
            for(int i=0;i<5;i++){
                if((temporary_bank->finish[i] == false)
                    &&(Judge_Add_To_Stack(temporary_bank->Need[i],temporary_bank->Available) == true)){
                    process_id_stack.push(i);
                    scene.push(temporary_bank);   //As above, can continue into the stack.
                }
                else{
                    miss += 1;     //Cannot add to stack.
                    if(miss == 5){     //miss = 5, the next round can not be stacked at all, proving that the previous round of stacking is not safe, at this time the top of the stack exactly refers to the previous round of stacking, just leave the stack.
                        process_id_stack.pop();           //id stack top element out of stack.
                        temporary_bank = scene.top();     //Resume the scene!
                        scene.pop();                      //When the site is restored, the site that exists in the stack is useless and goes out of the stack.
                    }
                }
            }
        }
        if(Judge_Simulation_End(temporary_bank) == true){
            return true;   //During the simulation, the process can all end and be safely scheduled
        }
    }
    free(temporary_bank);
    return false;
} //Security Check Function
bool Judge_Request(int Process_id,int* request,Bank* bank){
    if(bank->finish[Process_id] == true){
        cout<<"process"<<Process_id<<"The assignment has been completed"<<endl;
        return false;
    }   //1. The process that has completed the allocation of resources cannot be allocated any more.
    int count = 3;
    while(count){
        if(bank->Need[Process_id][count-1]<request[count-1]){
            cout<<"Request resources greater than required resources"<<endl;//2. Determine if the request is less than Need
            return false;
        }
        if(bank->Available[count-1]<request[count-1]){
            cout<<"Request resources are larger than existing resources"<<endl;//3. Determine if the request is less than Allocation
            return false;
        }
        count--;
    }
    //4. Finally, make a security check. If you pass the security check, you will prove that it is safe, otherwise it is not.
    return Judge_Safe(Process_id,request,bank);
} //Determine if the request can correspond to a function.
bool check_diedlock(Bank* bank){
    int count = 0;
    for(int i=0;i<5;i++){
        if(Judge_Add_To_Stack(bank->Need[i],bank->Available) == false){
            count++;
        }
    }
    if(count == 5){
        return true;
    }
    else{
        return false;
    }
}   //Check for deadlocks, if any, the operating system will not be saved. Deadlock means that Need of all five processes is greater than Alocation at this time. At this point, no matter how you toss, it is deadlock.
void print_table(Bank* bank){
    cout<<"         Allocation              Need                 Available"<<endl;
    cout<<"        A    B    C           A   B   C             A    B    C"<<endl;
    for(int i=0;i<5;i++){
        cout<<"P"<<i<<"      "<<bank->Allocation[i][0]<<"    "<<bank->Allocation[i][1]<<"    "<<bank->Allocation[i][2];
        cout<<"           "<<bank->Need[i][0]<<"   "<<bank->Need[i][1]<<"   "<<bank->Need[i][2];
        if(i == 0){
            cout<<"             "<<bank->Available[0]<<"    "<<bank->Available[1]<<"    "<<bank->Available[2];
        }
        cout<<endl;
    }
}   //Print the form on page P123 of the book to the terminal.
int main(){
    Bank* bank = new Bank();
    Change_Need_Matrix(bank);
    int id;
    int request_a;
    int request_b;
    int request_c;
    while(Judge_Simulation_End(bank) == false){   //As long as the process resource allocation is not complete, it remains while.
        cout<<"--------------------------------------------------------------------------------"<<endl;
        if(check_diedlock(bank) == true){
            cout<<"This problem deadlock,I can't do it either."<<endl;
            break;
        }  //Judge the deadlock first. If the problem itself is deadlocked, you won't have to fiddle around.
        /*
        Enter a request
        */
        cout<<"Please enter the process requesting the allocation of resources:";
        cin>>id;
        cout<<"Please enter the requested assignment A Number of class resources:";
        cin>>request_a;
        cout<<"Please enter the requested assignment B Number of class resources:";
        cin>>request_b;
        cout<<"Please enter the requested assignment C Number of class resources:";
        cin>>request_c;
        int request[3] = {request_a,request_b,request_c};
        if(Judge_Request(id,request,bank)==1){
            cout<<"The current request is secure and can be assigned as requested"<<endl;
            /*
            Since security is requested, resources are allocated.
            */
            bank->Need[id][0] -= request_a;
            bank->Need[id][1] -= request_b;
            bank->Need[id][2] -= request_c;

            bank->Allocation[id][0] += request_a;
            bank->Allocation[id][1] += request_b;
            bank->Allocation[id][2] += request_c;

            bank->Available[0] -= request_a;
            bank->Available[1] -= request_b;
            bank->Available[2] -= request_c;

            if((bank->Need[id][0] == 0)&&(bank->Need[id][1] == 0)&&(bank->Need[id][2] == 0)){
                bank->Available[0] += bank->Allocation[id][0];
                bank->Available[1] += bank->Allocation[id][1];
                bank->Available[2] += bank->Allocation[id][2];
                bank->finish[id] = true;
            }   //Finish executing this resource allocation request, and if a process finishes, its current finish is set to true.
            print_table(bank);  //Show the P123 page form to the user for the next input request.
        }
        else{
            /*
            The request is not secure, do nothing, and then wait for the user to enter the next request.
            */
            cout<<"Unsafe"<<endl;
            print_table(bank);  //Show the P123 page form to the user for the next input request.
        }
    }
    return 0;
}
Insert a code snippet here

The only benefit of writing this code is how to do security checks. As noted in the note, once a resource allocation sequence is found that meets the requirements, it can be demonstrated to be secure.
The author uses two stacks, one to save the process id number and the other to save the site, where the site refers to temporary_bank. Why save the scene? Because they may not be able to execute when they are doing security tests. But at this point it cannot be said that it is unsafe. For example, in the first round of allocation, the Need arrays of P1 and P4 correspond to a smaller Alocation than at this time. Whether P1 or P4 should be chosen is unknown. It's a bit like pruning here. Since P4 is better than P1, let's first assume that P4 is the way to go. If you take P4, Need of P4 is smaller than Allocation in the next step, then P4 is not the way to go. At this point, the top element of the stack is P4, and he can get out of the stack. After stacking, the top element of stack becomes P1, testing P1, P1 if possible, has security. If P1 doesn't work, P1 also gets the stack, and then the stack is empty, all state spaces are searched, and no suitable sequence of resource allocation is found. That means the current request Request is not secure and requires the user to re-enter a secure Request.
[Run result]
First Assignment

Change the request vector from P0 to Request(0,1,0).
Second allocation

P1 Request Resource Allocation
Third Assignment

P3 Request Resource Allocation
Fourth allocation

P0 Request Resource Allocation
Fifth Allocation

P2 Request Resource Allocation
Sixth allocation

P4 Request Resource Allocation
Resource allocation complete.
Here we can allocate resources manually or automatically using an algorithm.

Tags: Algorithm Operating System

Posted on Mon, 08 Nov 2021 20:55:39 -0500 by mrMarcus