Banker's algorithm

From Rosetta Code
Revision as of 21:46, 16 August 2017 by rosettacode>Carlo.milanesi (Added Rust language)
Banker's algorithm is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.
This page uses content from Wikipedia. The original article was at Banker's algorithm. The list of authors can be seen in the page history. As with Rosetta Code, the text of Wikipedia is available under the GNU FDL. (See links for details on variance)

The Banker's algorithm is a resource allocation and deadlock avoidance algorithm developed by Edsger Dijkstra that tests for safety by simulating the allocation of predetermined maximum possible amounts of all resources, and then makes a "s-state" check to test for possible deadlock conditions for all other pending activities, before deciding whether allocation should be allowed to continue.

Example input

Assuming that the system distinguishes between four types of resources, (A, B, C and D), the following is an example of how those resources could be distributed. Note that this example shows the system at an instant before a new request for resources arrives. Also, the types and number of resources are abstracted. Real systems, for example, would deal with much larger quantities of each resource.

Total resources in system:
A B C D
6 5 7 6
Available system resources are:
A B C D
3 1 1 2
Processes (currently allocated resources):
   A B C D
P1 1 2 2 1
P2 1 0 3 3
P3 1 2 1 0
Processes (maximum resources):
   A B C D
P1 3 3 2 2
P2 1 2 3 4
P3 1 3 5 0
Need= maximum resources - currently allocated resources
Processes (need resources):
   A B C D
P1 2 1 0 1
P2 0 2 0 1
P3 0 1 4 0

C

Standard binary heap-as-priority queue affair. Only that each node links back to its heap position for easier update.

There are two main() functions to choose from (look for #define BIG_EXAMPLE), one is for task example, the other is a much heavier duty test case. <lang c>#include <stdio.h>

  1. include <stdbool.h>

int main() {

   int curr[5][5];
   int max_claim[5][5];
   int avl[5];
   int alloc[5] = {0, 0, 0, 0, 0};
   int max_res[5];
   int running[5];
   int i, j, exec, r, p;
   int count = 0;
   bool safe = false;
   printf("\nEnter the number of resources: ");
   scanf("%d", &r);
   printf("\nEnter the number of processes: ");
   scanf("%d", &p);
   for (i = 0; i < p; i++) {
       running[i] = 1;
       count++;
   }
   printf("\nEnter Claim Vector: ");
   for (i = 0; i < r; i++)
       scanf("%d", &max_res[i]);
   printf("\nEnter Allocated Resource Table: ");
   for (i = 0; i < p; i++) {
       for (j = 0; j < r; j++)
           scanf("%d", &curr[i][j]);
   }
   printf("\nEnter Maximum Claim table: ");
   for (i = 0; i < p; i++) {
       for (j = 0; j < r; j++)
           scanf("%d", &max_claim[i][j]);
   }
   printf("\nThe Claim Vector is: ");
   for (i = 0; i < r; i++)
       printf("%d ", max_res[i]);
   printf("\nThe Allocated Resource Table:\n");
   for (i = 0; i < p; i++) {
       for (j = 0; j < r; j++)
           printf("\t%d", curr[i][j]);
       printf("\n");
   }
   printf("\nThe Maximum Claim Table:\n");
   for (i = 0; i < p; i++) {
       for (j = 0; j < r; j++)
           printf("\t%d", max_claim[i][j]);
       printf("\n");
   }
   for (i = 0; i < p; i++)
       for (j = 0; j < r; j++)
           alloc[j] += curr[i][j];
   printf("\nAllocated resources: ");
   for (i = 0; i < r; i++)
       printf("%d ", alloc[i]);
   for (i = 0; i < r; i++)
       avl[i] = max_res[i] - alloc[i];
   printf("\nAvailable resources: ");
   for (i = 0; i < r; i++)
       printf("%d ", avl[i]);
   printf("\n");
   while (count != 0) {
       safe = false;
       for (i = 0; i < p; i++) {
           if (running[i]) {
               exec = 1;
               for (j = 0; j < r; j++) {
                   if (max_claim[i][j] - curr[i][j] > avl[j]) {
                       exec = 0;
                       break;
                   }
               }
               if (exec) {
                   printf("\nProcess%d is executing.\n", i + 1);
                   running[i] = 0;
                   count--;
                   safe = true;
                   for (j = 0; j < r; j++)
                       avl[j] += curr[i][j];
                   break;
               }
           }
       }
       if (!safe) {
           printf("\nThe processes are in unsafe state.");
           break;
       }
       if (safe)
           printf("\nThe process is in safe state.");
       printf("\nAvailable vector: ");
       for (i = 0; i < r; i++)
           printf("%d ", avl[i]);
   }
   return 0;

}</lang>

Input and Output:
Enter the number of resources: 4

Enter the number of processes: 5

Enter Claim Vector: 8 5 9 7

Enter Allocated Resource Table: 2 0 1 1 0 1 2 1 4 0 0 3 0 2 1 0 1 0 3 0

Enter Maximum Claim table: 3 2 1 4 0 2 5 2 5 1 0 5 1 5 3 0 3 0 3 3

The Claim Vector is: 8 5 9 7
The Allocated Resource Table:
        2       0       1       1
        0       1       2       1
        4       0       0       3
        0       2       1       0
        1       0       3       0

The Maximum Claim Table:
        3       2       1       4
        0       2       5       2
        5       1       0       5
        1       5       3       0
        3       0       3       3

Allocated resources: 7 3 7 5
Available resources: 1 2 2 2

Process3 is executing.

The process is in safe state.
Available vector: 5 2 2 5
Process1 is executing.

The process is in safe state.
Available vector: 7 2 3 6
Process2 is executing.

The process is in safe state.
Available vector: 7 3 5 7
Process4 is executing.

The process is in safe state.
Available vector: 7 5 6 7
Process5 is executing.

The process is in safe state.
Available vector: 8 5 9 7

Racket

<lang racket>#lang racket/base (require racket/block racket/pretty racket/port racket/vector)

(pretty-print-columns 20) ; make the matrices look a bit more matrixey

(define (bankers-algorithm p r maxres curr maxclaim)

 (define running? (make-vector p #t))
 (define alloc (for/vector #:length r ((j (in-range r)))
                 (for/sum ((cu_i (in-vector curr))) (vector-ref cu_i j))))
 (printf "Allocated resources:~%~a~%" (pretty-format alloc))
 (define avl (for/vector #:length r ((m (in-vector maxres)) (a (in-vector alloc))) (- m a)))
 (printf "Available resources:~%~a~%~%" (pretty-format avl))
 
 (define (safe-exec i mc_i cu_i)
   (define exec? (for/and ((a (in-vector avl)) (m (in-vector mc_i)) (c (in-vector cu_i)))
                   (<= (- m c) a)))
   (cond
     [exec?
      (printf "Process ~a is executing~%" (add1 i))
      (vector-set! running? i #f)
      (for ((j (in-range r)) (a (in-vector avl)) (c (in-vector cu_i))) (vector-set! avl j (+ a c)))
      #t]
     [else #f]))
 
 (let loop ()
   (unless (zero? (vector-count values running?))
     (define safe?
       (for/first ((i (in-range p))
                   (r? (in-vector running?))
                   (mc_i (in-vector maxclaim))
                   (cu_i (in-vector curr))
                   ;; the break condition for this is identical to safe?, so we have no
                   ;; separate break? flag
                   #:when r?
                   #:when (safe-exec i mc_i cu_i))
         #t))
     (cond [safe?
            (printf "The process is in a safe state~%~%Available vector: ~a~%" (pretty-format avl))
            (loop)]
           [else (displayln "The processes are in an unsafe state")]))))


(define (bankers-input)

 (define ((n-vector? type? dims) x) ;; not the world's most efficient implementation!
   (cond [(null? dims) (type? x)]
         [(not (vector? x)) #f]
         [(not (= (car dims) (vector-length x))) #f]
         [else (for/and ((e (in-vector x))) (n-vector? type? (cdr dims)) e)]))
 
 (define-syntax-rule (prompted-input prompt valid?)
   (block
    (printf "Enter ~a:~%" prompt)
    (define rv (read))
    (pretty-print rv)
    (unless (valid? rv) (raise-argument-error 'prompted-input (format "~a" 'valid?) rv))
    rv))
 
 (define p (prompted-input "the number of processes" exact-positive-integer?))
 (define r (prompted-input "the number of resources" exact-positive-integer?))
 (define maxres (prompted-input "Claim Vector" (n-vector? exact-positive-integer? (list r))))
 (define curr (prompted-input "Allocated Resource Table"
                              (n-vector? exact-positive-integer? (list p r))))
 (define maxclaim (prompted-input "Maximum Claim Table"
                                  (n-vector? exact-positive-integer? (list p r))))
 (values p r maxres curr maxclaim))

(module+ main

 (with-input-from-string
  #<<EOS

5 4

  1. (8 5 9 7)
  2. (#(2 0 1 1)
 #(0 1 2 1)
 #(4 0 0 3)
 #(0 2 1 0)
 #(1 0 3 0))
  1. (#(3 2 1 4)
 #(0 2 5 2)
 #(5 1 0 5)
 #(1 5 3 0)
 #(3 0 3 3))

EOS

  (λ () (call-with-values bankers-input bankers-algorithm))))</lang>
Output:
Enter the number of processes:
5
Enter the number of resources:
4
Enter Claim Vector:
'#(8 5 9 7)
Enter Allocated Resource Table:
'#(#(2 0 1 1)
   #(0 1 2 1)
   #(4 0 0 3)
   #(0 2 1 0)
   #(1 0 3 0))
Enter Maximum Claim Table:
'#(#(3 2 1 4)
   #(0 2 5 2)
   #(5 1 0 5)
   #(1 5 3 0)
   #(3 0 3 3))
Allocated resources:
'#(7 3 7 5)
Available resources:
'#(1 2 2 2)

Process 3 is executing
The process is in a safe state

Available vector: '#(5 2 2 5)
Process 1 is executing
The process is in a safe state

Available vector: '#(7 2 3 6)
Process 2 is executing
The process is in a safe state

Available vector: '#(7 3 5 7)
Process 4 is executing
The process is in a safe state

Available vector: '#(7 5 6 7)
Process 5 is executing
The process is in a safe state

Available vector: '#(8 5 9 7)

rust

Adapted from the C language version. It crashes for invalid input.

<lang rust> fn read_numbers<T>() -> Vec<T> where T: std::str::FromStr {

   use std::io::Write;
   std::io::stdout().flush().unwrap();
   let mut line = String::new();
   std::io::stdin().read_line(&mut line).unwrap();
   line.split(" ").map(|word| word.trim().parse::<T>().ok().unwrap()).collect()

}

fn main() {

   print!("Enter the number of resources: ");
   let r = read_numbers()[0];
   
   print!("Enter the number of processes: ");
   let p = read_numbers()[0];
   let mut running = vec![true; p];
   let mut count = p;
   
   print!("Enter the {}-item claim vector: ", r);
   let max_res = read_numbers::<u32>();
   println!("Enter the {}-line {}-column allocated-resource table:", p, r);
   let mut curr = vec![vec![0; 0]; p];
   for i in 0..p {
       curr[i] = read_numbers::<u32>();
   }
   
   println!("Enter the {}-line {}-column maximum-claim table:", p, r);
   let mut max_claim = vec![vec![0; 0]; p];
   for i in 0..p {
       max_claim[i] = read_numbers::<u32>();
   }
   
   print!("The claim vector is: ");
   for i in 0..r {
       print!("{} ", max_res[i]);
   }
   println!();
   println!("The allocated resources table is:");
   for i in 0..p {
       for j in 0..r {
           print!("\t{}", curr[i][j]);
       }
       println!();
   }
   println!("The maximum claims table is:");
   for i in 0..p {
       for j in 0..r {
           print!("\t{}", max_claim[i][j]);
       }
       println!();
   }
   
   let mut alloc = vec![0; r];
   for i in 0..p {
       for j in 0..r {
           alloc[j] += curr[i][j];
       }
   }
   
   print!("The allocated resources are: ");
   for i in 0..r {
       print!("{} ", alloc[i]);
   }
   println!();
   let mut avl = vec![0; r];
   for i in 0..r {
       avl[i] = max_res[i] - alloc[i];
   }
   print!("The available resources are: ");
   for i in 0..r {
       print!("{} ", avl[i]);
   }
   println!();
   while count != 0 {
       let mut safe = false;
       for i in 0..p {
           if running[i] {
               let mut exec = true;
               for j in 0..r {
                   if max_claim[i][j] - curr[i][j] > avl[j] {
                       exec = false;
                       break;
                   }
               }
               if exec {
                   println!("Process {} is executing.", i + 1);
                   running[i] = false;
                   count -= 1;
                   safe = true;
                   for j in 0..r {
                       avl[j] += curr[i][j];
                   }
                   break;
               }
           }
       }
       if safe {
           println!("The process is in safe state.");
       }
       else {
           println!("The processes are in unsafe state.");
           break;
       }
       print!("The available vector is: ");
       for i in 0..r {
           print!("{} ", avl[i]);
       }
       println!();
   }

} </lang>

Input and Output:
Enter the number of resources: 4
Enter the number of processes: 5
Enter the 4-item claim vector: 8 5 9 7
Enter the 5-line 4-column allocated-resource table:
2 0 1 1
0 1 2 1
4 0 0 3
0 2 1 0
1 0 3 0
Enter the 5-line 4-column maximum-claim table:
3 2 1 4
0 2 5 2
5 1 0 5
1 5 3 0
3 0 3 3
The claim vector is: 8 5 9 7 
The allocated resources table is:
	2	0	1	1
	0	1	2	1
	4	0	0	3
	0	2	1	0
	1	0	3	0
The maximum claims table is:
	3	2	1	4
	0	2	5	2
	5	1	0	5
	1	5	3	0
	3	0	3	3
The allocated resources are: 7 3 7 5 
The available resources are: 1 2 2 2 
Process 3 is executing.
The process is in safe state.
The available vector is: 5 2 2 5 
Process 1 is executing.
The process is in safe state.
The available vector is: 7 2 3 6 
Process 2 is executing.
The process is in safe state.
The available vector is: 7 3 5 7 
Process 4 is executing.
The process is in safe state.
The available vector is: 7 5 6 7 
Process 5 is executing.
The process is in safe state.
The available vector is: 8 5 9 7