Professional Documents
Culture Documents
Efficient utilization of the central processing unit (CPU) is crucial for optimizing
system performance in modern computer operating systems. CPU scheduling algorithms
play a vital role in determining the order in which processes are executed and the allocation
of CPU time. This abstract provides a comprehensive overview and comparative analysis
of various CPU scheduling algorithms, including First-Come-First-Serve (FCFS), Shortest
Job First (SJF), Shortest Remaining Time First (SRTF), Round Robin (RR), Preemptive,
and Non-Preemptive.
The FCFS algorithm follows a simple and intuitive approach, executing processes in the
order they arrive. However, it may suffer from poor average waiting times, especially when
long processes arrive before shorter ones. SJF, on the other hand, prioritizes processes with
the shortest burst time, resulting in minimized average waiting times. However, it can lead
to starvation for longer processes.
SRTF is a preemptive variant of SJF where the CPU is allocated to the process with the
shortest remaining burst time. This algorithm provides even better performance in terms of
average waiting times but requires frequent context switching, which can incur overhead.
Round Robin scheduling is a popular algorithm that assigns fixed time slices to each process
in a circular manner. This ensures fairness among processes and prevents starvation.
However, it may lead to increased waiting times for long processes, known as the "convoy
effect."
- If the running process finishes or is blocked, the next process in the ready queue is
selected for execution.
- The process with the shortest burst time is selected for execution.
- When a process arrives, its burst time is compared with the burst times of the processes
in the ready queue.
- If the arriving process has a shorter burst time, it is selected for execution.
- If the running process finishes or is blocked, the process with the shortest burst time in
the ready queue is selected.
- Similar to SJF, but the process with the shortest remaining burst time is selected for
execution.
- When a process arrives, its remaining burst time is compared with the remaining burst
times of the processes in the ready queue.
- If the arriving process has a shorter remaining burst time, it preempts the currently
running process and takes its place.
- The next process in the ready queue is selected for execution, and the cycle continues.
- If a process does not finish within its time slice, it is moved to the end of the ready queue.
5. Preemptive Scheduling:
6. Non-Preemptive Scheduling:
- The scheduler does not preempt a running process and allows it to run until completion.
Implementation
#include <stdio.h>
struct Process {
int process_id;
int burst_time;
int priority;
};
void fcfs(struct Process processes[], int n) {
int waiting_time[n], turnaround_time[n];
waiting_time[0] = 0;
turnaround_time[0] = processes[0].burst_time;
for (int i = 1; i < n; i++) {
waiting_time[i] = processes[i - 1].burst_time + waiting_time[i - 1];
turnaround_time[i] = processes[i].burst_time + waiting_time[i];
}
printf("FCFS:\n");
for (int i = 0; i < n; i++) {
printf("Process %d: Waiting Time = %d, Turnaround Time = %d\n",
processes[i].process_id,
waiting_time[i], turnaround_time[i]);
}
}
void sjn(struct Process processes[], int n) {
int waiting_time[n], turnaround_time[n];
int burst_time_remaining[n];
for (int i = 0; i < n; i++) {
burst_time_remaining[i] = processes[i].burst_time;
}
int complete = 0;
int current_time = 0;
int min_burst_index = 0;
while (complete != n) {
for (int i = 0; i < n; i++) {
if (processes[i].burst_time < processes[min_burst_index].burst_time &&
burst_time_remaining[i] > 0) {
min_burst_index = i;
}
}
burst_time_remaining[min_burst_index] -= 1;
if (burst_time_remaining[min_burst_index] == 0) {
complete += 1;
int end_time = current_time + 1;
waiting_time[min_burst_index] = end_time - processes[min_burst_index].burst_time;
turnaround_time[min_burst_index] = end_time;
min_burst_index = (min_burst_index + 1) % n;
}
current_time += 1;
}
printf("\nSJN:\n");
for (int i = 0; i < n; i++) {
printf("Process %d: Waiting Time = %d, Turnaround Time = %d\n", processes[i].process_id,
waiting_time[i], turnaround_time[i]);
}
}
void priority_scheduling(struct Process processes[], int n) {
int waiting_time[n], turnaround_time[n];
int burst_time_remaining[n];
for (int i = 0; i < n; i++) {
burst_time_remaining[i] = processes[i].burst_time;
}
int complete = 0;
int current_time = 0;
int min_priority_index = 0;
while (complete != n) {
for (int i = 0; i < n; i++) {
if (processes[i].priority < processes[min_priority_index].priority &&
burst_time_remaining[i] > 0) {
min_priority_index = i;
}
}
burst_time_remaining[min_priority_index] -= 1;
if (burst_time_remaining[min_priority_index] == 0) {
complete += 1;
int end_time = current_time + 1;
waiting_time[min_priority_index] = end_time - processes[min_priority_index].burst_time;
turnaround_time[min_priority_index] = end_time;
min_priority_index = (min_priority_index + 1) % n;
}
current_time += 1;
}
printf("\nPriority Scheduling:\n");
for (int i = 0; i < n; i++) {
printf("Process %d: Waiting Time = %d, Turnaround Time = %d\n", processes[i].process_id,
waiting_time[i], turnaround_time[i]);
}
}
void round_robin(struct Process processes[], int n, int time_quantum) {
int remaining_burst_time[n];
for (int i = 0; i < n; i++) {
remaining_burst_time[i] = processes[i].burst_time;
}
int waiting_time[n], turnaround_time[n];
int current_time = 0;
int complete = 0;
while (complete != n) {
for (int i = 0; i < n; i++) {
if (remaining_burst_time[i] > time_quantum) {
remaining_burst_time[i] -= time_quantum;
current_time += time_quantum;
}
else if (remaining_burst_time[i] > 0) {
current_time += remaining_burst_time[i];
waiting_time[i] = current_time - processes[i].burst_time;
remaining_burst_time[i] = 0;
complete += 1;
}
}
}
for (int i = 0; i < n; i++) {
turnaround_time[i] = processes[i].burst_time + waiting_time[i];
}
printf("\nRound Robin:\n");
for (int i = 0; i < n; i++) {
printf("Process %d: Waiting Time = %d, Turnaround Time = %d\n", processes[i].process_id,
waiting_time[i], turnaround_time[i]);
}
}
int main() {
struct Process processes[] = {
{1, 10, 2},
{2, 5, 0},
{3, 8, 1},
{4, 6, 3}
};
int n = sizeof(processes) / sizeof(processes[0]);
int time_quantum = 3;
fcfs(processes, n);
sjn(processes, n);
priority_scheduling(processes, n);
round_robin(processes, n, time_quantum);
return 0;
}
Output:
FCFS:
Process 1: Waiting Time = 0, Turnaround Time = 10
Process 2: Waiting Time = 10, Turnaround Time = 15
Process 3: Waiting Time = 15, Turnaround Time = 23
Process 4: Waiting Time = 23, Turnaround Time = 29
SJN:
Process 1: Waiting Time = 5, Turnaround Time = 15
Process 2: Waiting Time = 0, Turnaround Time = 5
Process 3: Waiting Time = 15, Turnaround Time = 23
Process 4: Waiting Time = 23, Turnaround Time = 29
Priority Scheduling:
Process 1: Waiting Time = 5, Turnaround Time = 15
Process 2: Waiting Time = 15, Turnaround Time = 20
Process 3: Waiting Time = 0, Turnaround Time = 8
Process 4: Waiting Time = 23, Turnaround Time = 29
Round Robin:
Process 1: Waiting Time = 6, Turnaround Time = 16
Process
Conculsion
- May lead to longer waiting times for processes with larger burst times.
- The process with the smallest remaining burst time is executed first.
- Requires preemption and frequent context switching, which can incur overhead.
5. Preemptive Scheduling:
- Requires efficient process management and may lead to frequent context switching.
6. Non-preemptive Scheduling: