Implementation of Priority Scheduling Algorithm in C++

In this post, we implement the Priority Scheduling CPU scheduling algorithm in C++. Each process is assigned a priority number, and the process with the highest priority is scheduled first. This algorithm is used in real-time and embedded systems where certain tasks are more urgent than others and must preempt routine work.

What is Priority Scheduling?

In this implementation, a higher priority number means higher urgency (e.g., priority 5 executes before priority 1). The algorithm is non-preemptive — once a process starts, it runs to completion. All processes are assumed to arrive at time 0.

The algorithm works by sorting processes in descending order of priority and then computing scheduling metrics in that order:

  • Waiting Time (WT): WT[i] = WT[i-1] + BurstTime[i-1] (since all arrive at time 0)
  • Turnaround Time (TT): TT[i] = WT[i] + BurstTime[i]

The main concern with priority scheduling is starvation — low-priority processes may never get the CPU. The solution is aging: gradually increasing a process’s priority the longer it waits.


C++ Code Implementation

// ============================================================
// Priority Scheduling Algorithm in C++ (Non-Preemptive)
// Higher priority number = higher urgency = runs first
// All processes arrive at time 0
// ============================================================

#include <iostream>
using namespace std;

// Holds all scheduling attributes for a single process
struct Process {
    int processNo;      // Original process number (preserved after sorting)
    int arrivalTime;    // Arrival time (0 for all processes in this example)
    int burstTime;      // CPU time required to complete the process
    int priorityLevel;  // Priority value — higher number = higher urgency
    int waitingTime;    // Time the process spends waiting before execution
    int turnaroundTime; // Total time from arrival to completion
};

int main() {

    const int PROCESS_COUNT = 4;
    Process processes[PROCESS_COUNT];

    // -------------------------------------------------------
    // Step 1: Read burst time and priority for each process
    // -------------------------------------------------------
    for (int i = 0; i < PROCESS_COUNT; i++) {
        cout << "\n Enter burst time of P" << i + 1 << ": ";
        cin  >> processes[i].burstTime;
        cout << " Enter priority of P"    << i + 1 << " (higher = more urgent): ";
        cin  >> processes[i].priorityLevel;
        processes[i].processNo   = i + 1;
        processes[i].arrivalTime = 0;   // All processes arrive at time 0
    }

    // Display entered data
    cout << "\n\n Entered Data";
    cout << "\n PNO\tAT\tBT\tPriority";
    for (int i = 0; i < PROCESS_COUNT; i++) {
        cout << "\n P" << processes[i].processNo
             << "\t" << processes[i].arrivalTime
             << "\t" << processes[i].burstTime
             << "\t" << processes[i].priorityLevel;
    }

    // -------------------------------------------------------
    // Step 2: Sort processes by priority (descending — highest first)
    // -------------------------------------------------------
    for (int outer = 0; outer < PROCESS_COUNT - 1; outer++) {
        for (int inner = outer + 1; inner < PROCESS_COUNT; inner++) {
            // If outer process has lower priority, swap with inner
            if (processes[outer].priorityLevel < processes[inner].priorityLevel) {
                Process temp         = processes[outer];
                processes[outer]     = processes[inner];
                processes[inner]     = temp;
            }
        }
    }
    // After sorting: processes[0] has the highest priority

    // -------------------------------------------------------
    // Step 3: Calculate Waiting Time and Turnaround Time
    // Since all processes arrive at time 0, WT[i] = sum of all previous burst times
    // -------------------------------------------------------
    processes[0].waitingTime    = 0;
    processes[0].turnaroundTime = processes[0].burstTime;
    int totalBurstTime = processes[0].burstTime;

    for (int i = 1; i < PROCESS_COUNT; i++) {
        // With AT=0 for all, no gap correction needed
        processes[i].waitingTime =
            processes[i-1].waitingTime + processes[i-1].burstTime;

        processes[i].turnaroundTime =
            processes[i].waitingTime + processes[i].burstTime;

        totalBurstTime += processes[i].burstTime;
    }

    // -------------------------------------------------------
    // Step 4: Display results table
    // -------------------------------------------------------
    cout << "\n\n Result (sorted by priority — highest first)";
    cout << "\n PNO\tAT\tPriority\tWT\tBT\tTT";
    for (int i = 0; i < PROCESS_COUNT; i++) {
        cout << "\n P" << processes[i].processNo
             << "\t" << processes[i].arrivalTime
             << "\t" << processes[i].priorityLevel
             << "\t\t" << processes[i].waitingTime
             << "\t" << processes[i].burstTime
             << "\t" << processes[i].turnaroundTime;
    }
    cout << "\n Total Burst Time: " << totalBurstTime;

    // -------------------------------------------------------
    // Step 5: Compute averages
    // -------------------------------------------------------
    int totalWaiting = 0, totalTurnaround = 0;
    for (int i = 0; i < PROCESS_COUNT; i++) {
        totalWaiting    += processes[i].waitingTime;
        totalTurnaround += processes[i].turnaroundTime;
    }

    cout << "\n Average Waiting Time    : " << (float)totalWaiting    / PROCESS_COUNT;
    cout << "\n Average Turnaround Time : " << (float)totalTurnaround / PROCESS_COUNT;
    cout << endl;

    return 0;
}

Explanation of the Code

  1. Process struct — The field priorityLevel holds the urgency value. Naming it priorityLevel (rather than just p) avoids confusion since the array of processes is also commonly named p. processNo is stored separately so the original process identity is preserved after sorting.
  2. Sorting by priorityLevel (descending) — The inner loop condition processes[outer].priorityLevel < processes[inner].priorityLevel swaps whenever the outer process has lower priority, pushing the highest-priority process to index 0.
  3. Waiting Time simplification — Since all processes arrive at time 0, the formula reduces to: WT[i] = WT[i-1] + BT[i-1]. There is no arrival-gap correction needed.
  4. Turnaround TimeTT = WT + BurstTime for each process after sorting.

Sample Output

 Enter burst time of P1: 5
 Enter priority of P1 (higher = more urgent): 4
 Enter burst time of P2: 3
 Enter priority of P2 (higher = more urgent): 1
 Enter burst time of P3: 6
 Enter priority of P3 (higher = more urgent): 5
 Enter burst time of P4: 2
 Enter priority of P4 (higher = more urgent): 2

 Entered Data
 PNO    AT      BT      Priority
 P1     0       5       4
 P2     0       3       1
 P3     0       6       5
 P4     0       2       2

 Result (sorted by priority — highest first)
 PNO    AT      Priority    WT      BT      TT
 P3     0       5           0       6       6
 P1     0       4           6       5       11
 P4     0       2           11      2       13
 P2     0       1           13      3       16

 Total Burst Time: 16
 Average Waiting Time    : 7.5
 Average Turnaround Time : 11.5

Step-by-Step Explanation of Input/Output

After sorting by priority (descending): P3(P=5) → P1(P=4) → P4(P=2) → P2(P=1)

Gantt Chart:

| P3 (0–6) | P1 (6–11) | P4 (11–13) | P2 (13–16) |
  • P3 (Priority 5, highest): Executes first. WT = 0. TT = 0 + 6 = 6.
  • P1 (Priority 4): Starts at time 6. WT = 6. TT = 6 + 5 = 11.
  • P4 (Priority 2): Starts at time 11. WT = 11. TT = 11 + 2 = 13.
  • P2 (Priority 1, lowest): Executes last. WT = 13. TT = 13 + 3 = 16.
  • Average WT = (0 + 6 + 11 + 13) / 4 = 30 / 4 = 7.5
  • Average TT = (6 + 11 + 13 + 16) / 4 = 46 / 4 = 11.5

P2 with the lowest priority (1) waits the longest — 13 units — demonstrating the starvation risk in priority scheduling when low-priority processes keep being bypassed.


See Also

Bottom line is…

Priority Scheduling gives critical processes first access to the CPU, making it well-suited for real-time and embedded systems. Its chief weakness is starvation of low-priority processes, which is solved by aging — incrementally boosting the priority of processes that have been waiting a long time. In modern OSes, priority scheduling is combined with time-slicing (as in Linux’s Completely Fair Scheduler) to balance both priority and fairness.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.