In this post, we implement the Banker’s Algorithm in C++ — a classic deadlock avoidance mechanism in operating systems proposed by Edsger Dijkstra. The algorithm is named after the analogy of a bank that never lends money in a way that could prevent it from satisfying all customers’ future needs.
What is the Banker’s Algorithm?
Before granting any resource request, the OS runs the Banker’s Algorithm to check whether doing so keeps the system in a safe state. A safe state is one where a safe sequence exists — an ordering of all processes such that each can eventually complete using currently available resources plus the resources released by earlier processes in the sequence.
If no safe sequence exists, the state is unsafe, meaning deadlock is possible. The OS denies the request in that case.
Three data structures are needed:
- Available[] — Current free units of each resource type.
- Allocated[][] — Resources currently held by each process.
- Maximum[][] — The maximum resources each process may ever request.
- Need[][] — Remaining resources a process may still request:
Need[i][j] = Maximum[i][j] - Allocated[i][j]
C++ Code Implementation
// ============================================================
// Banker's Algorithm in C++ — Deadlock Avoidance
// Determines if the current resource allocation is in a safe state
// System: 4 processes (P0–P3), 4 resource types (R0–R3)
// ============================================================
#include <iostream>
using namespace std;
int main() {
const int PROCESS_COUNT = 4; // Number of processes
const int RESOURCE_COUNT = 4; // Number of distinct resource types
// Currently available units of each resource type
int availableResources[RESOURCE_COUNT] = {3, 1, 1, 2};
// Resources currently allocated to each process
// allocatedResources[i][j] = units of resource j held by process i
int allocatedResources[PROCESS_COUNT][RESOURCE_COUNT] = {
{1, 2, 2, 1}, // Process 0 currently holds: R0=1, R1=2, R2=2, R3=1
{1, 1, 3, 3}, // Process 1 currently holds: R0=1, R1=1, R2=3, R3=3
{1, 1, 1, 0}, // Process 2 currently holds: R0=1, R1=1, R2=1, R3=0
{3, 2, 1, 1} // Process 3 currently holds: R0=3, R1=2, R2=1, R3=1
};
// Maximum resources each process may ever need
// maximumResources[i][j] = max units of resource j process i may request
int maximumResources[PROCESS_COUNT][RESOURCE_COUNT] = {
{3, 3, 2, 2}, // Process 0 may need at most: R0=3, R1=3, R2=2, R3=2
{1, 7, 3, 4}, // Process 1 may need at most: R0=1, R1=7, R2=3, R3=4
{1, 1, 5, 0}, // Process 2 may need at most: R0=1, R1=1, R2=5, R3=0
{2, 2, 3, 3} // Process 3 may need at most: R0=2, R1=2, R2=3, R3=3
};
// -------------------------------------------------------
// Step 1: Compute Need matrix = Maximum - Allocated
// -------------------------------------------------------
int needMatrix[PROCESS_COUNT][RESOURCE_COUNT];
for (int proc = 0; proc < PROCESS_COUNT; proc++) {
for (int res = 0; res < RESOURCE_COUNT; res++) {
needMatrix[proc][res] =
maximumResources[proc][res] - allocatedResources[proc][res];
}
}
// -------------------------------------------------------
// Step 2: Display the system state
// -------------------------------------------------------
cout << "\n Allocated Resources:";
for (int proc = 0; proc < PROCESS_COUNT; proc++) {
cout << "\n P" << proc << ": ";
for (int res = 0; res < RESOURCE_COUNT; res++)
cout << allocatedResources[proc][res] << " ";
}
cout << "\n\n Maximum Resources:";
for (int proc = 0; proc < PROCESS_COUNT; proc++) {
cout << "\n P" << proc << ": ";
for (int res = 0; res < RESOURCE_COUNT; res++)
cout << maximumResources[proc][res] << " ";
}
cout << "\n\n Need Matrix (Maximum - Allocated):";
for (int proc = 0; proc < PROCESS_COUNT; proc++) {
cout << "\n P" << proc << ": ";
for (int res = 0; res < RESOURCE_COUNT; res++)
cout << needMatrix[proc][res] << " ";
}
cout << "\n\n Available Resources: ";
for (int res = 0; res < RESOURCE_COUNT; res++)
cout << availableResources[res] << " ";
// -------------------------------------------------------
// Step 3: Safety Algorithm
// workPool[] simulates the available pool as processes finish.
// finished[] tracks which processes have completed.
// -------------------------------------------------------
int workPool[RESOURCE_COUNT]; // Simulated available pool
bool finished[PROCESS_COUNT] = {false}; // All processes unfinished initially
int safeSequence[PROCESS_COUNT]; // Stores the safe execution order
int scheduledCount = 0; // Number of processes scheduled so far
// Initialize work pool with current available resources
for (int res = 0; res < RESOURCE_COUNT; res++)
workPool[res] = availableResources[res];
bool progressMade;
do {
progressMade = false;
for (int proc = 0; proc < PROCESS_COUNT; proc++) {
if (!finished[proc]) {
// Check if ALL resource needs of this process can be satisfied
bool canFinish = true;
for (int res = 0; res < RESOURCE_COUNT; res++) {
if (needMatrix[proc][res] > workPool[res]) {
canFinish = false; // Not enough of resource 'res' available
break;
}
}
if (canFinish) {
// Process can complete — add its allocation back to the work pool
for (int res = 0; res < RESOURCE_COUNT; res++)
workPool[res] += allocatedResources[proc][res];
safeSequence[scheduledCount++] = proc; // Add to safe sequence
finished[proc] = true; // Mark as done
progressMade = true; // At least one process progressed
}
}
}
} while (progressMade); // Keep scanning until no more progress is possible
// -------------------------------------------------------
// Step 4: Determine if system is safe or unsafe
// -------------------------------------------------------
if (scheduledCount == PROCESS_COUNT) {
cout << "\n\n System is in a SAFE STATE.";
cout << "\n Safe Sequence: ";
for (int i = 0; i < PROCESS_COUNT; i++) {
cout << "P" << safeSequence[i];
if (i < PROCESS_COUNT - 1) cout << " -> ";
}
} else {
cout << "\n\n System is in an UNSAFE STATE — Deadlock may occur!";
cout << "\n Processes that could NOT be scheduled: ";
for (int proc = 0; proc < PROCESS_COUNT; proc++)
if (!finished[proc]) cout << "P" << proc << " ";
}
cout << endl;
return 0;
}
Explanation of the Code
- Need Matrix — Computed as
Maximum - Allocated. Tells the algorithm how many more resources each process may still request. All names are descriptive:needMatrix,allocatedResources,maximumResources. - Work Pool —
workPool[]starts as a copy ofavailableResources[]and grows as processes complete and release their allocations. It simulates the state of available resources as the safe sequence executes. - Safety Loop — The
do-whileloop repeatedly scans all unfinished processes looking for one whose entireneedMatrix[proc]row is ≤workPool[]. When found, it simulates that process finishing and addsallocatedResources[proc]back toworkPool[]. The loop continues as long as at least one process makes progress (progressMade). - Safe vs Unsafe — If
scheduledCount == PROCESS_COUNT, every process was scheduled — safe state. Otherwise, some processes are stuck — unsafe state with potential deadlock.
Sample Output
Allocated Resources:
P0: 1 2 2 1
P1: 1 1 3 3
P2: 1 1 1 0
P3: 3 2 1 1
Maximum Resources:
P0: 3 3 2 2
P1: 1 7 3 4
P2: 1 1 5 0
P3: 2 2 3 3
Need Matrix (Maximum - Allocated):
P0: 2 1 0 1
P1: 0 6 0 1
P2: 0 0 4 0
P3: -1 0 2 2
Available Resources: 3 1 1 2
System is in a SAFE STATE.
Safe Sequence: P0 -> P2 -> P3 -> P1
Step-by-Step Explanation of Input/Output
Starting with Available = {3, 1, 1, 2}:
- P0: Need = {2,1,0,1} ≤ Available = {3,1,1,2} ✓. P0 runs and releases {1,2,2,1}. Available becomes {4,3,3,3}.
- P2: Need = {0,0,4,0} ≤ {4,3,3,3} ✓. P2 runs and releases {1,1,1,0}. Available becomes {5,4,4,3}.
- P3: Need = {-1,0,2,2} — negative need means process already holds more than enough for R0. All needs effectively ≤ available ✓. P3 runs and releases {3,2,1,1}. Available grows further.
- P1: Need = {0,6,0,1} ≤ current available ✓. P1 runs. All 4 processes complete. Safe Sequence: P0 → P2 → P3 → P1.
See Also
Bottom line is…
The Banker’s Algorithm guarantees deadlock-free operation by ensuring the system never enters an unsafe state. Its main practical limitation is that processes must declare their maximum resource needs upfront, which is not always feasible. It also adds overhead on every resource request. Modern systems often prefer deadlock detection-and-recovery over avoidance, but the Banker’s Algorithm remains a foundational concept for understanding how resource allocation can be made safe.