Round Robin in OS
Introduction
Round Robin (RR) is a preemptive CPU scheduling algorithm that gives each process a fixed time slice (time quantum) in a cyclic order. It ensures fair CPU allocation and is ideal for time-sharing systems. Think of it like a multiplayer board game – every player (process) gets an equal turn, no matter how long their task takes!
Key Characteristics
- Preemptive: The CPU can be taken away from a process.
- Time Quantum (TQ): Fixed time each process can run before being rotated.
- Circular Ready Queue: Processes are requeued if unfinished.
- No Starvation: All processes eventually get their turn.
Problem Statement
Calculate the Average Waiting Time and Average Turnaround Time using Round Robin for the following processes with time quantum = 2 units.
Process | Arrival Time | Burst Time |
---|---|---|
P1 | 0 | 6 |
P2 | 0 | 3 |
P3 | 0 | 4 |
Time Quantum = 2
Step-by-Step Simulation
We’ll simulate each time unit, tracking:
- The ready queue
- The currently running process
- Updates to burst time and completed processes
Initial Setup
- Time = 0
- Ready Queue = [P1, P2, P3] (All arrived at time 0 and we will push based on Arrival Time)
Cycle 1: Time 0 to 2
- P1 is dequeued and runs for 2 units
- Remaining Burst Time: P1 = 4
- P1 is requeued
- 🔁 Queue = [P2, P3, P1]
Cycle 2: Time 2 to 4
- P2 runs for 2 units → Remaining = 1
- P2 is requeued
- 🔁 Queue = [P3, P1, P2]
Cycle 3: Time 4 to 6
- P3 runs for 2 units → Remaining = 2
- P3 is requeued
- 🔁 Queue = [P1, P2, P3]
Cycle 4: Time 6 to 8
- P1 runs again → Remaining = 2
- P1 is requeued
- 🔁 Queue = [P2, P3, P1]
Cycle 5: Time 8 to 9
- P2 runs for 1 unit and finishes!
- Completion Time of P2 = 9
- ✅ P2 exits
- 🔁 Queue = [P3, P1]
Cycle 6: Time 9 to 11
- P3 runs for 2 units and finishes!
- Completion Time of P3 = 11
- ✅ P3 exits
- 🔁 Queue = [P1]
Cycle 7: Time 11 to 13
- P1 runs final 2 units and finishes!
- Completion Time of P1 = 13
- ✅ P1 exits
- 🔁 Queue = []
Final Completion Times
Process | Completion Time |
---|---|
P1 | 13 |
P2 | 9 |
P3 | 11 |
Turnaround Time = Completion - Arrival
Process | Turnaround Time |
---|---|
P1 | 13 - 0 = 13 |
P2 | 9 - 0 = 9 |
P3 | 11 - 0 = 11 |
Average Turnaround Time = (13 + 9 + 11) / 3 = 11.0
Waiting Time = Turnaround - Burst
Process | Waiting Time |
---|---|
P1 | 13 - 6 = 7 |
P2 | 9 - 3 = 6 |
P3 | 11 - 4 = 7 |
Average Waiting Time = (7 + 6 + 7) / 3 = 6.67
Gantt Chart Representation
0──2──4──6──8──9──11──13
|P1|P2|P3|P1|P2|P3 |P1 |
C Implementation of Round Robin Algorithm
#include <stdio.h>
#include <stdlib.h>
#define MAX 100
struct Process {
int pid;
int arrival;
int burst;
int remaining;
int completion;
int turnaround;
int waiting;
int started;
};
void enqueue(int queue[], int *rear, int value) {
queue[++(*rear)] = value;
}
int dequeue(int queue[], int *front, int *rear) {
if (*front > *rear) return -1;
return queue[(*front)++];
}
int isInQueue(int queue[], int front, int rear, int pid) {
for (int i = front; i <= rear; i++) {
if (queue[i] == pid) return 1;
}
return 0;
}
int main() {
int n, timeQuantum;
printf("Enter number of processes: ");
scanf("%d", &n);
struct Process p[n];
for (int i = 0; i < n; i++) {
p[i].pid = i + 1;
printf("Enter Arrival Time and Burst Time for P%d: ", p[i].pid);
scanf("%d %d", &p[i].arrival, &p[i].burst);
p[i].remaining = p[i].burst;
p[i].started = 0;
}
printf("Enter Time Quantum: ");
scanf("%d", &timeQuantum);
int queue[MAX], front = 0, rear = -1;
int time = 0, completed = 0;
int gantt[100], ganttCount = 0;
// Enqueue initially available processes
for (int i = 0; i < n; i++) {
if (p[i].arrival == time) {
enqueue(queue, &rear, i);
p[i].started = 1;
}
}
while (completed < n) {
if (front > rear) {
time++;
// Check for new arrivals
for (int i = 0; i < n; i++) {
if (p[i].arrival <= time && !p[i].started) {
enqueue(queue, &rear, i);
p[i].started = 1;
}
}
continue;
}
int i = dequeue(queue, &front, &rear);
int runTime = (p[i].remaining < timeQuantum) ? p[i].remaining : timeQuantum;
printf("\n🟢 Time %d-%d: P%d running", time, time + runTime, p[i].pid);
gantt[ganttCount++] = p[i].pid;
time += runTime;
p[i].remaining -= runTime;
// Check for new arrivals during this time slice
for (int j = 0; j < n; j++) {
if (p[j].arrival > (time - runTime) && p[j].arrival <= time && !p[j].started) {
enqueue(queue, &rear, j);
p[j].started = 1;
}
}
if (p[i].remaining == 0) {
p[i].completion = time;
p[i].turnaround = p[i].completion - p[i].arrival;
p[i].waiting = p[i].turnaround - p[i].burst;
completed++;
printf(" (Completed ✅)");
} else {
enqueue(queue, &rear, i); // not done, requeue
printf(" (Requeued 🔁)");
}
// Print Ready Queue state
printf("\n📥 Ready Queue: [");
for (int k = front; k <= rear; k++) {
printf("P%d", p[queue[k]].pid);
if (k != rear) printf(" ");
}
printf("]");
}
// Final process table
float totalTAT = 0, totalWT = 0;
printf("\n\n📊 Final Table:\n");
printf("PID Arrival Burst Completion Turnaround Waiting\n");
for (int i = 0; i < n; i++) {
printf("P%-4d%-9d%-7d%-12d%-11d%-7d\n", p[i].pid, p[i].arrival, p[i].burst,
p[i].completion, p[i].turnaround, p[i].waiting);
totalTAT += p[i].turnaround;
totalWT += p[i].waiting;
}
printf("\n🔁 Gantt Chart (Timeline):\n| ");
for (int i = 0; i < ganttCount; i++) {
printf("P%d | ", gantt[i]);
}
printf("\n");
printf("\n📈 Average Turnaround Time: %.2f", totalTAT / n);
printf("\n📉 Average Waiting Time : %.2f\n", totalWT / n);
return 0;
}
Sample Output
Enter number of processes: 3
Enter Arrival Time and Burst Time for P1: 0 6
Enter Arrival Time and Burst Time for P2: 0 3
Enter Arrival Time and Burst Time for P3: 0 4
Enter Time Quantum: 2
🟢 Time 0-2: P1 running (Requeued 🔁)
📥 Ready Queue: [P2 P3 P1]
🟢 Time 2-4: P2 running (Requeued 🔁)
📥 Ready Queue: [P3 P1 P2]
🟢 Time 4-6: P3 running (Requeued 🔁)
📥 Ready Queue: [P1 P2 P3]
🟢 Time 6-8: P1 running (Requeued 🔁)
📥 Ready Queue: [P2 P3 P1]
🟢 Time 8-9: P2 running (Completed ✅)
📥 Ready Queue: [P3 P1]
🟢 Time 9-11: P3 running (Completed ✅)
📥 Ready Queue: [P1]
🟢 Time 11-13: P1 running (Completed ✅)
📥 Ready Queue: []
📊 Final Table:
PID Arrival Burst Completion Turnaround Waiting
P1 0 6 13 13 7
P2 0 3 9 9 6
P3 0 4 11 11 7
🔁 Gantt Chart (Timeline):
| P1 | P2 | P3 | P1 | P2 | P3 | P1 |
📈 Average Turnaround Time: 11.00
📉 Average Waiting Time : 6.67
0.00s user 0.00s system 0% cpu 7.176 total
Pros & Cons of Round Robin
Advantages
- Equal CPU sharing → prevents starvation
- Great for time-sharing systems
- More responsive than FCFS
Disadvantages
- Context switching overhead
- Poor average turnaround for short jobs if quantum is large
When to Use Round Robin
- OS-level CPU scheduling in multi-user systems
- Interactive applications where fairness matters
FAQ
Q: Can I tune the time quantum?
Yes! Choose 10–100ms depending on the system load and context switch cost.
Q: What if new processes arrive during execution?
They’re placed at the end of the queue and get CPU in future rounds.
Q: Is Round Robin optimal?
No. It prioritizes fairness over turnaround or waiting time.