# Operating system experiment 2: banker algorithm

## Banker Algorithm

### 1, Experiment content

Banker algorithm is used to avoid deadlock, realize the rational allocation of resources, and deepen the understanding of process synchronization and deadlock.

### 2, Experimental requirements

1. Suppose that the system has three kinds of resources A (10), B (15) and C (12), and five processes execute concurrently. The process scheduling adopts the time slice rotation scheduling algorithm.
2. Each process is represented by a process control block (PCB), which can contain the following information: process name, total required resources, allocated resources, and process status.
3. The process is automatically generated by the program (including the required data, and pay attention to the reasonable range of data).
4. During the process of running, a process will randomly request resources (randomly generate the number of requested resources). If the maximum demand is reached, it means that the process can be completed; If the maximum demand is not reached, schedule other processes to run after running a time slice. Banker algorithm is used to avoid deadlock in resource allocation.
5. The status of each process can be one of ready W (Wait), running R (Run), blocking B (Block), or completed F (Finish).
6. For each scheduling, the program will output the running results: the running process, the process in the ready queue, the process in the blocking queue, the completed process and the PCB of each process for inspection.

### 3, Algorithm flow

#### 3.1 header file and data structure

```#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define TIME_SLICE 2

// Process status: ready to wait for blocking to complete
enum process_type{
process_type_wait = 'W',
process_type_run = 'R',
process_type_block = 'B',
process_type_finish = 'F'
};

typedef struct PCB{
// Process name
char name;
// Maximum required resources
int Max[100];
// Number of additional resources required
int Need[100];
// Number of resources allocated
int Allocate[100];
// Process elapsed time
int run_time;
// Process status
char state;
// Point to next process
PCB *next;
}PCB;

// Name of system resource
char Name[100]={0};
// System available resource vector
int Available[100];
// Process request resource vector
int Request[100];
// Available resources of storage system
int Work[100];
// Whether the marking system has enough resources allocated to each process
bool Finish[100];
// Store safety sequence
char Security[100];

// Maximum number of processes
int M = 100;
// Maximum number of resources
int N = 100;
// Flag output
bool flag = true;
```
```// Function declaration
// Initialization data
void init(PCB *list);
// Create process
void create_process(PCB *list);
// Display resource allocation and process operation
void print(PCB *list);
// Tentative allocation of resources
void test(PCB *list);
// Tentative resource allocation void
void Retest(PCB *list);
// Try to score application resources by banker algorithm
bool bank(PCB *list);
// Security algorithm
bool safe(PCB *list);
// Time slice rotation scheduling algorithm
void round_robin(PCB *list);
```

#### 3.2 main function

```// Main function
int main(){
printf("-----------------------------------------------------------------------\n");
printf("||                        Implementation of banker algorithm                           ||\n");
printf("-----------------------------------------------------------------------\n\n");
PCB *list = (PCB *)malloc(sizeof(PCB));
if(list == NULL){
printf("Dynamic memory allocation failed!");
}
list->next = NULL;

srand((int)time(NULL));
// Initialization data
init(list);
// Display resource allocation and process operation
printf("***********************************************************************\n");
print(list);
// Banker algorithm is used to determine whether the system is safe at the current time. If it is not safe, resources will no longer be allocated
if(!safe(list)) {
exit(0);
}
printf("\n***********************************************************************\n");
// Process scheduling using time slice rotation method
round_robin(list);
}
```

#### 3.3 initialization data

```// Initialization data
void init(PCB *list){
// m is the number of processes, n is the type of system resources
int m,n;
// Initialize the number of system resource types and resources
printf("The types of resources available to the system are:");
scanf("%d",&n);
// The number of system resource types, which is assigned to the global variable N to facilitate subsequent methods
N = n;
// Resource name
char name;
// Number of resources
int number;
for(int i = 1;i <= n;i++){
printf("\t resources%d Name of:",i);
getchar();
scanf("%c",&name);
Name[i] = name;
printf("\t resources%c The initial number of is:",name);
scanf("%d",&number);
Available[i] = number;
}
// The number of initialization processes and the maximum number of resources required by each process
printf("\n Please enter the number of processes:");
scanf("%d",&m);
// The number of processes, assigned to the global variable M, is convenient for subsequent methods
M = m;
create_process(list);
}
```

#### 3.4 create process

```// Create process
void create_process(PCB *list){
// Count allocated system resources
int temp[100] = {0};
int number = 1;
while(number <= M){
// Process node
PCB *p = (PCB *)malloc(sizeof(PCB));
if(p == NULL){
printf("Dynamic memory allocation failed!");
}
// Process name
printf("\t Please enter page%d Process name of the process:",number);
getchar();
scanf("%c",&p->name);
// Flag variable
bool flag;
// Initialize the maximum number of resources required, the number of resources still required, and the number of allocated resources for each process
do{
flag = false;
for(int i = 1;i <= N;i++){
p->Max[i] = rand()%10;
if(p->Max[i] > Available[i]){
flag = true;
// printf("the maximum resource demand is greater than the maximum number of resources in the system, please re-enter! \n");
break;
}
p->Need[i] = p->Max[i];
p->Allocate[i] = 0;
}
}while(flag);
// Process elapsed time
p->run_time = 0;
// Process status
p->state = process_type_wait;
// Point to next process
p->next = NULL;
if(list->next == NULL){
list->next = p;
}else{
PCB *move = list->next;
while(move->next != NULL){
move = move->next;
}
move->next = p;
}
number++;
}
printf("\n");
}
```

#### 3.5 display resource allocation and process operation

```// Display resource allocation and process operation
void print(PCB *list){
printf("\n Resources currently available in the system(Available):\n");
for(int i = 1;i <= N;i++){
printf("%c  ",Name[i]);
}
printf("\n");
for(int i = 1;i <= N;i++){
printf("%d  ",Available[i]);
}
printf("\n\n");
printf("The current resource allocation and process operation of the system are as follows:\n");
printf("          Max        Allocate        Need\n");
printf("Process name  ");
//Output the resource name that goes with the process name, corresponding to Max, Allocate and Need respectively
for(int i = 1;i <= 3;i++){
for(int j = 1;j <= N;j++){
printf("%c  ",Name[j]);
}
printf("     ");
}
printf("Run time process status\n");

PCB *p = list->next;
while(p != NULL){
//Output Max, Allocation and Need of each process
printf("  %c\t",p->name);
for(int j = 1;j <= N;j++)
printf("%d  ",p->Max[j]);
printf("     ");
for(int j = 1;j <= N;j++)
printf("%d  ",p->Allocate[j]);
printf("     ");
for(int j = 1;j <= N;j++)
printf("%d  ",p->Need[j]);
printf("        ");
printf("  %d\t  ",p->run_time);
printf("%c\n",p->state);
p = p->next;
}
}
```

#### 3.6 tentative allocation of resources

```// Tentative allocation of resources
void test(PCB *list){
// Process requesting resources
PCB *p = list->next;
// Change process information
for(int i = 1;i <= N;i++){
Available[i] -= Request[i];
p->Allocate[i] += Request[i];
p->Need[i] -= Request[i];
}
}
```

#### 3.7 cancellation of tentatively allocated resources

```// Tentative resource allocation void
void Retest(PCB *list){
// Process requesting resources
PCB *p = list->next;
// Contrary to test operation
for(int i = 1;i <= N;i++){
Available[i] += Request[i];
p->Allocate[i] -= Request[i];
p->Need[i] += Request[i];
}
}
```

#### 3.8 trial scoring of application resources by banker algorithm

```// Try to score application resources by banker algorithm
bool bank(PCB *list){
PCB *p = list->next;
// Randomly generate request vector
for(int i = 1;i <= N;++i){
Request[i] = rand()%(p->Need[i]+1);
}
// The number of randomly generated request resources is 0, indicating that they are ignored
int n = 0;
for(int i = 1;i <= N;++i){
if(Request[i] == 0){
n++;
}
}
if(n == N){
flag = false;
return false;
}
printf("\n%c Process request—— ",p->name);
for(int i = 1;i <= N;i++){
printf("resources%c: ",Name[i]);
printf("%d   ",Request[i]);
}
printf("\n\n");
// Locate the required resource array subscript
int num = 1;
// Judge whether the first two conditions of banker algorithm are true
for(int i = 1;i <= N;++i){
// Judge whether the application is greater than the demand. If it is greater than the demand, an error will occur
if(Request[i] > p->Need[i]){
printf("%c The process requested more resources than it needed\n",p->name);
printf("Unreasonable distribution, no distribution!\n");
return false;
}else{
// Judge whether the application is greater than the current allocable resources. If it is greater than, an error will occur
if(Request[i] > Available[i]){
printf("%c The resources requested by the process are greater than the resources currently available to the system\n",p->name);
printf("The system does not have enough resources and will not be allocated!\n");
return false;
}
}
}
// If the first two conditions are true, try to allocate resources and find a safe sequence
// Try to allocate resources according to the process demand
test(list);
// Judge whether the system is safe
if(!safe(list)){
Retest(list);
return false;
}
return true;
}
```

#### 3.9 security algorithm

```// Security algorithm
bool safe(PCB *list){
// Count the number of incomplete processes
int m = 0;
PCB *move = list->next;
while(move != NULL && move->state != process_type_finish){
move = move->next;
++m;
}
// Initialize Work array
for(int i = 1;i <= N;i++){
Work[i] = Available[i];
}
// Initialize Finish array
for(int i = 1;i <= M;i++){
if(i <= m){
Finish[i] = false;
}else{
Finish[i] = true;
}
}
// Node location to judge the process running
int pnum = 1,apply;
int num = 1;
// Secure sequence
PCB *p = list->next;
while(p != NULL && pnum <= m){
apply = 0;
for(int i = 1;i <= N;i++){
// The current process is incomplete and various resources are less than or equal to the number of system resources
if(Finish[pnum] == false && p->Need[i] <= Work[i]){
apply++;
// Allocation is not allowed until the required number of resources of each type is less than the available resources of the system
if(apply == N){
for(int x = 1;x <= N;x++){
// Update current system allocable resources
Work[x] += p->Allocate[x];
}
// Update tag array
Finish[pnum] = true;
// Update safe sequence array
Security[num++] = p->name;
// Ensure that each query starts from the first process
pnum = 0;
p = list;
}
}
}
// Query next process
pnum++;
p = p->next;
}
for(int i = 1;i <= M;i++){
if(Finish[i] == false){
// The system is in an unsafe state
printf("The system is unsafe!\n");
return false;
}
}
// If safe, output safe sequence
printf("The system is safe!\n");
printf("There is a security sequence:");
for(int i = 1;i <= m;i++){
// Output process run order array
printf(" %c ",Security[i]);
if(i < m){
printf("->");
}
}
printf("\n");
return true;
}
```

#### 3.10 time slice rotation scheduling algorithm

```// Time slice rotation scheduling algorithm
void round_robin(PCB *list){
// Record the position of the first node
PCB *index = list->next;
while (index != NULL && index->state != process_type_finish) {
// Judge whether to output after scheduling
flag = true;
// System security, processes allocated to resources and running
if(bank(list)){
// Update elapsed time
index->run_time += TIME_SLICE;
// Determine whether the process is completed
int num = 0;
for(int i = 1;i <= N;++i){
if(index->Max[i] == index->Allocate[i]){
num++;
}
}
// The process is complete
if (num == N) {
// Modify process status
index->state = process_type_finish;
// Reclaim allocated resources
for(int i = 1;i <= N;i++){
Available[i] += index->Allocate[i];
}
printf("%c Process complete\n",index->name);
}else{
// The process is not completed, enter and wait
index->state = process_type_wait;
}
// Current process completed
if (index->state == process_type_finish){
// Adjust the completed process to the end of the completed queue
// 1. the header pointer points to the next node of the initial node
list->next = index->next;
// 2. traverse the entire linked list and insert it to the end of the completed queue
PCB *p = list;
while (p->next != NULL) {
p = p->next;
}
p->next = index;
index->next = NULL;
} else {
// Current process not completed
// 1. the header pointer points to the next node of the initial node
list->next = index->next;
// 2. traverse the entire linked list and insert it into the end of the waiting queue (followed by the completed queue)
PCB *p = list;
// 2.1 finding the insertion position
while (p->next != NULL && p->next->state != process_type_finish) {
p = p->next;
}
// 2.2 determining the insertion position
if (p->next == NULL) {
// the last one
p->next = index;
p->next->next = NULL;
}else{
// Not the last one, there are still nodes after it
index->next = p->next;
p->next = index;
}
}
}else{
// The resource allocation requested by this process will lead to unsafe system or unreasonable resource request
// Block and adjust the process to the middle of the waiting queue and the completed queue, and it is the last one in the blocking queue
index->state = process_type_block;
// The current process is incomplete and blocked
// 1. the header pointer points to the next node of the initial node
list->next = index->next;
// 2. traverse the entire linked list and insert it into the last block queue after the unfinished queue
PCB *p = list;
// 2.1 finding the insertion position
while (p->next != NULL && p->next->state != process_type_finish) {
p = p->next;
}
// 2.2 determining the insertion position
if (p->next == NULL) {
// the last one
p->next = index;
p->next->next = NULL;
}else{
// Not the last one, there are still nodes after it
index->next = p->next;
p->next = index;
}
}
// Show current queue status
if(list->next->state != process_type_finish){
list->next->state = process_type_run;
}
if(flag){
print(list);
printf("\n***********************************************************************\n");
}
index = list->next;
}
}
```

### 4, Experimental results (screenshot):

The code comments are very detailed and can be run by yourself. The screenshot of the experiment can be run by yourself

### 5, Analysis:

In this experiment, the time slice round robin scheduling algorithm is used to schedule multiple randomly generated processes. The banker algorithm first checks the legitimacy of the resource requests proposed by the processes, that is, to check whether the requests are not greater than what the processes need or the system can use. If the request is legal, trial allocation will be conducted. Finally, the security of the state call security algorithm after the trial allocation is checked. If the system is safe, that is, there is a safe execution sequence. As long as the system allocates all the resources required by the process according to this process sequence, each process can be successfully executed. If not, it will not be allocated, restore the original state, and reject the application. In this way, when the system is allocating resources, the system can not enter an unsafe state and can well avoid deadlock.
The code written in this experiment is redundant, and it can be optimized by modifying the data structure used. For example, the maximum required resource array Max, the required resource array Need and the allocated resource array Allocate in the PCB structure are replaced with three structure pointers, that is, a resource structure is established, which contains various resource variables of the system, and the three structure pointers point to this structure, This is a good way to optimize the code, but it also has a small drawback, that is, the number of resource types cannot be entered manually. It needs to be set in the code in advance. When the number of resource types needs to be changed, the source code needs to be changed, which is not very consistent with the OOP principle (open to extension and closed to modification). Therefore, it is not used in this experiment, but if there is a way to optimize the data structure again to solve this problem, the data structure is a better choice.

Posted by gfmitchell on Thu, 02 Jun 2022 00:24:51 +0530