FCFS and SJF
CPU Scheduling in Operating Systems:
In the context of operating systems, CPU scheduling involves determining which process (or task) should be executed next by the central processing unit (CPU).
The goal is to maximize CPU utilization, minimize waiting time, and ensure fair allocation of resources.
Various scheduling algorithms are used to achieve these objectives.
First-Come-First-Serve (FCFS) Scheduling:
Definition:
- FCFS is the simplest CPU scheduling algorithm.
- It is non-preemptive, meaning once a process starts executing, it cannot be interrupted until completion.
- Processes are placed in a queue based on their arrival time.
- The process that arrives first gets executed first.
Execution Order:
- Processes are executed in the order they arrive.
- The process at the front of the queue is selected for execution.
Advantages:
- Easy to implement.
- Minimal overhead.
Disadvantages:
- Often results in long waiting times.
- Leads to the convoy effect (where a long process holds up other processes).
Shortest Job First (SJF) Scheduling:
Definition:
- SJF selects the process with the smallest burst time for execution next.
- It can be either preemptive or non-preemptive.
- Preemptive SJF is also known as Shortest Remaining Time First (SRTF).
- Processes are ordered based on their burst times (ascending order).
- The process with the shortest burst time is executed first.
- Minimizes average waiting time.
- Efficient for minimizing turnaround time.
- Long processes may suffer from starvation (never get executed).
- Requires knowing burst times in advance (which is often not feasible).
- FCFS executes processes in arrival order, while SJF prioritizes the shortest job.
- FCFS leads to lower device and CPU utilization, whereas SJF aims for higher effectiveness by reducing average waiting time.
- FCFS does not suffer from starvation, but SJF may if long processes are continuously preempted.
In summary, FCFS is straightforward but can lead to inefficiencies, while SJF optimizes waiting time but may cause starvation for longer processes.
Let’s start by creating the Gantt charts for the First-Come-First-Serve (FCFS) and Shortest Job First (SJF) scheduling algorithms based on the given processes, CPU burst times, and arrival times. After that, we’ll compute the average waiting time and average turnaround time for each algorithm.
Table
FCFS (First-Come-First-Serve) Scheduling:
Arrange the processes in the order of their arrival times.
Execute the processes in the order they appear in the queue.
Gantt Chart for FCFS:
P1 (0–8 ms)
P2 (8–9 ms)
P3 (9–12 ms)
P4 (12–14 ms)
P5 (14–20 ms)
P3 (9–12 ms)
P4 (12–14 ms)
P5 (14–20 ms)
Turnaround Time (TAT) for each process:
TAT=Completion Time-Arrival Time
TAT(P1) = Completion Time(P1) - Arrival Time(P1) = 8 - 0 = 8 ms
TAT(P2) = 9 - 1 = 8 ms
TAT(P3) = 12 - 2 = 10 ms
TAT(P4) = 14 - 3 = 11 ms
TAT(P5) = 20 - 4 = 16 ms
Average Turnaround Time = (8 + 8 + 10 + 11 + 16) / 5 = 10.6 ms
TAT(P2) = 9 - 1 = 8 ms
TAT(P3) = 12 - 2 = 10 ms
TAT(P4) = 14 - 3 = 11 ms
TAT(P5) = 20 - 4 = 16 ms
Average Turnaround Time = (8 + 8 + 10 + 11 + 16) / 5 = 10.6 ms
We can also find TAT using this formula if the waiting time is known
TAT=Waiting Time + Burst Time
TAT(P1)=0+8=8ms
TAT(P2)=7+1=8ms
TAT(P3)=7+3=10ms
TAT(P4)=9+2=11ms
TAT(P5)=10+6=16ms
Waiting Time (WT) for each process:
Waiting Time (WT) for each process:
WT(P1) = TAT(P1) - Burst Time(P1) = 8 - 8 = 0 ms
WT(P2) = 8 - 1 = 7 ms
WT(P3) = 10 - 3 = 7 ms
WT(P4) = 11 - 2 = 9 ms
WT(P5) = 16 - 6 = 10 ms
Average Waiting Time = (0 + 7 + 7 + 9 + 10) / 5 = 6.6 ms
WT(P2) = 8 - 1 = 7 ms
WT(P3) = 10 - 3 = 7 ms
WT(P4) = 11 - 2 = 9 ms
WT(P5) = 16 - 6 = 10 ms
Average Waiting Time = (0 + 7 + 7 + 9 + 10) / 5 = 6.6 ms
We can also find the waiting time recursively
WT(P1)=0
WT(P2)=ArrivalTime(P1)+WT(P1)+BurstTime(P1)-ArrivalTime(P2)=0+0+8-1=7ms
WT(P3)=ArrivalTime(P2)+WT(P2)+BurstTime(P2)-ArrivalTime(P3)=1+7+1-2=7ms
WT(P4)=ArrivalTime(P3)+WT(P3)+BurstTime(P3)-ArrivalTime(P4)=2+7+3-3=9ms
WT(P5)=ArrivalTime(P4)+WT(P4)+BurstTime(P4)-ArrivalTime(P5)=3+9+2-4=10ms
//****************************************************************************//
// C Program Implementation of FCFS Scheduling
//****************************************************************************//
#include <stdio.h>
void findWaitingTime(int processes[], int n, int bt[], int wt[],int at[]) {
wt[0] = 0;
for (int i = 1; i < n; i++)
wt[i] = at[i-1]+ wt[i - 1]+bt[i - 1] -at[i];
}
void findTurnAroundTime(int processes[], int n, int bt[], int wt[],int at[], int tat[]) {
for (int i = 0; i < n; i++)
tat[i] = wt[i]+bt[i];
}
void findAvgTime(int processes[], int n, int bt[], int at[]) {
int wt[n], tat[n], total_wt = 0, total_tat = 0;
findWaitingTime(processes, n, bt, wt,at);
findTurnAroundTime(processes, n, bt, wt,at, tat);
printf("Processes\tArrival time\tBurst time\tWaiting time\tTurnaround time\n");
for (int i = 0; i < n; i++) {
total_wt += wt[i];
total_tat += tat[i];
printf("%d\t\t%d\t\t%d\t\t%d\t\t%d\n", i + 1, at[i],bt[i], wt[i], tat[i]);
}
printf("Average waiting time = %.2f\n", (float)total_wt / n);
printf("Average turnaround time = %.2f\n", (float)total_tat / n);
}
int main() {
int processes[] = {1, 2, 3,4,5};
int n = sizeof(processes) / sizeof(processes[0]);
int burst_time[] = {8,1,3,2,6};
int arrival_time[] = {0,1,2,3,4};
findAvgTime(processes, n, burst_time, arrival_time);
return 0;
}
Output:
Processes Arrival time Burst time Waiting time Turnaround time
1 0 8 0 8
2 1 1 7 8
3 2 3 7 10
4 3 2 9 11
5 4 6 10 16
Average waiting time = 6.60
Average turnaround time = 10.60
An alternate and efficient implementation with structures
#include <stdio.h>
// Structure to represent a process
typedef struct {
int name; // Process name (1, 2, 3, ...)
int arrival; // Arrival time
int burst; // Burst time
int completion; //Completion time
int waiting; //waiting time
int turnaround; //turn around time
} Process;
int main() {
// Define the processes
Process processes[] = {
{1, 0,8}, // Arrival time = 0, Burst time = 8
{2, 1,1}, // Arrival time = 1, Burst time = 1
{3, 2,3}, // Arrival time = 2, Burst time = 3
{4, 3,2},// Arrival time = 3, Burst time = 2
{5, 4,6} // Arrival time = 4, Burst time = 6
};
int n = sizeof(processes) / sizeof(Process); // Number of processes
// Initialize variables
int currenttime = 0;
printf("Time | Process\n");
printf("------+-------------------\n");
// Iterate through each process
for (int i = 0; i < n; i++) {
// Check if the process has arrived and is not yet completed
int execution_time = processes[i].burst;
currenttime += execution_time;
// Print the execution
printf("%-5d | P%d\n", currenttime, processes[i].name);
processes[i].completion=currenttime;
processes[i].turnaround=processes[i].completion-processes[i].arrival;
processes[i].waiting=processes[i].turnaround-processes[i].burst;
}
float avgwt=0.0;
float avgtat=0.0;
printf("Process ArrivalTime BurstTime TurnaroundTime WaitingTime\n");
for(int i=0;i<n;i++)
{
printf("P%d%10d%10d%15d%20d\n",processes[i].name,processes[i].arrival,processes[i].burst,processes[i].turnaround,processes[i].waiting);
avgwt=avgwt+processes[i].waiting;
avgtat=avgtat+processes[i].turnaround;
}
printf("Average Waiting Time=%f\n",avgwt/n);
printf("Average turnaround Time=%f\n",avgtat/n);
return 0;
}
// Structure to represent a process
typedef struct {
int name; // Process name (1, 2, 3, ...)
int arrival; // Arrival time
int burst; // Burst time
int completion; //Completion time
int waiting; //waiting time
int turnaround; //turn around time
} Process;
int main() {
// Define the processes
Process processes[] = {
{1, 0,8}, // Arrival time = 0, Burst time = 8
{2, 1,1}, // Arrival time = 1, Burst time = 1
{3, 2,3}, // Arrival time = 2, Burst time = 3
{4, 3,2},// Arrival time = 3, Burst time = 2
{5, 4,6} // Arrival time = 4, Burst time = 6
};
int n = sizeof(processes) / sizeof(Process); // Number of processes
// Initialize variables
int currenttime = 0;
printf("Time | Process\n");
printf("------+-------------------\n");
// Iterate through each process
for (int i = 0; i < n; i++) {
// Check if the process has arrived and is not yet completed
int execution_time = processes[i].burst;
currenttime += execution_time;
// Print the execution
printf("%-5d | P%d\n", currenttime, processes[i].name);
processes[i].completion=currenttime;
processes[i].turnaround=processes[i].completion-processes[i].arrival;
processes[i].waiting=processes[i].turnaround-processes[i].burst;
}
float avgwt=0.0;
float avgtat=0.0;
printf("Process ArrivalTime BurstTime TurnaroundTime WaitingTime\n");
for(int i=0;i<n;i++)
{
printf("P%d%10d%10d%15d%20d\n",processes[i].name,processes[i].arrival,processes[i].burst,processes[i].turnaround,processes[i].waiting);
avgwt=avgwt+processes[i].waiting;
avgtat=avgtat+processes[i].turnaround;
}
printf("Average Waiting Time=%f\n",avgwt/n);
printf("Average turnaround Time=%f\n",avgtat/n);
return 0;
}
Time | Process
------+-------------------
8 | P1
9 | P2
12 | P3
14 | P4
20 | P5
Process ArrivalTime BurstTime TurnaroundTime WaitingTime
P1 0 8 8 0
P2 1 1 8 7
P3 2 3 10 7
P4 3 2 11 9
P5 4 6 16 10
Average Waiting Time=6.600000
Average turnaround Time=10.600000
------+-------------------
8 | P1
9 | P2
12 | P3
14 | P4
20 | P5
Process ArrivalTime BurstTime TurnaroundTime WaitingTime
P1 0 8 8 0
P2 1 1 8 7
P3 2 3 10 7
P4 3 2 11 9
P5 4 6 16 10
Average Waiting Time=6.600000
Average turnaround Time=10.600000
SJF (Shortest Job First) Scheduling: ( Non Preemptive)
Lets consider all job arrive at time 0
Process Burst Time
P1 8ms
P2 1ms
P3 3ms
P4 2ms
P5 6ms
Gantt Chart:
P2 (0-1ms)
P4 (1–3 ms)
P3 (3–6 ms)
P5 (6–12 ms)
P1 (12–20 ms)
P3 (3–6 ms)
P5 (6–12 ms)
P1 (12–20 ms)
Waiting Time (WT):
WT(P2)=0
WT(P4)=WT(P2)+Burst Time(P2) etc
P2: 0 ms
P4: 1 ms
P3: 3 ms
P5: 6 ms
P1: 12 ms
Average WT: (0 + 1+ 3 + 6 + 12) / 5 = 4.4 ms
Turnaround Time (TAT):
TAT=WT+Burst Time
P2:0+1= 1 ms
P4: 1+2=3 ms
P3: 3+3=6 ms
P5: 6+6=12 ms
P1: 12+8=20 ms
Average TAT: (1 + 3 + 6 + 12 + 20) / 5 = 8.4 ms
P4: 1+2=3 ms
P3: 3+3=6 ms
P5: 6+6=12 ms
P1: 12+8=20 ms
Average TAT: (1 + 3 + 6 + 12 + 20) / 5 = 8.4 ms
The SJF algorithm results in the minimum average waiting time among all other scheduling algorithms.
//**********************************************************
//C program SJF Non Preemptive Scheduling
//**********************************************************
#include <stdio.h>
#include <stdbool.h>
// Structure to represent a process
struct Process {
int pid; // Process ID
int arrival_time; // Arrival time
int burst_time; // Burst time
};
// Function to sort processes based on burst time
void sortProcesses(struct Process processes[], int n) {
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (processes[j].burst_time > processes[j + 1].burst_time) {
// Swap processes[j] and processes[j + 1]
struct Process temp = processes[j];
processes[j] = processes[j + 1];
processes[j + 1] = temp;
}
}
}
}
// Function to calculate waiting time and turnaround time
void calculateTimes(struct Process processes[], int n, int wt[], int tat[]) {
wt[0] = 0;
tat[0]=wt[0]+processes[0].burst_time;
for (int i = 1; i < n; i++) {
wt[i] = wt[i - 1] + processes[i - 1].burst_time;
tat[i] = wt[i] + processes[i].burst_time;
}
}
// Function to calculate average waiting time and turnaround time
void calculateAvgTimes(struct Process processes[], int n) {
int wt[n], tat[n];
calculateTimes(processes, n, wt, tat);
float avg_wt = 0, avg_tat = 0;
printf("PID \tWT \tTAT\n");
for (int i = 0; i < n; i++) {
avg_wt += wt[i];
avg_tat += tat[i];
printf("%d\t %d\t %d\n",processes[i].pid,wt[i],tat[i]);
}
printf("Average waiting time = %.2f\n", avg_wt / n);
printf("Average turnaround time = %.2f\n", avg_tat / n);
}
int main() {
int n = 5; // Number of processes
struct Process processes[] = {
{1, 0, 8},
{2, 1, 1},
{3, 2, 3},
{4, 3, 2},
{5, 4, 6}
};
// Sort processes based on burst time
sortProcesses(processes, n);
// Calculate average waiting time and turnaround time
calculateAvgTimes(processes, n);
return 0;
}
Output:
PID WT TAT
2 0 1
4 1 3
3 3 6
5 6 12
1 12 20
Average waiting time = 4.40
Average turnaround time = 8.40
SJF (Shortest Job First) Scheduling: ( Preemptive)
Gantt Chart:
Gantt Chart:
P1 (0-1ms) 7 remaining
P2 (1–2 ms) completed P2
P3 (2–3 ms) 2 remaining
P4 (3–5 ms) completed P4
P3 (2–3 ms) 2 remaining
P4 (3–5 ms) completed P4
P3(5-7 ms) completed P3
P5 (7–13 ms) completed P5
P1 (13–20 ms) completed P1
Turnaround Time (TAT):
P5 (7–13 ms) completed P5
P1 (13–20 ms) completed P1
Turnaround Time (TAT):
P1: 20 ms
P2: 1 ms
P3: 3 ms
P4: 4 ms
P5: 9 ms
Average TAT: (20 + 1 + 3 + 4 + 9) / 5 = 7.4 ms
Waiting Time (WT):
P2: 1 ms
P3: 3 ms
P4: 4 ms
P5: 9 ms
Average TAT: (20 + 1 + 3 + 4 + 9) / 5 = 7.4 ms
Waiting Time (WT):
P1: 12 ms
P2: 0 ms
P3: 2 ms
P4: 0 ms
P5: 3 ms
Average WT: (12 + 0 + 2 + 0 + 3) / 5 = 3.4 ms
//******************************************************************
// C Program SJF Preemptive scheduling
//******************************************************************
#include <stdio.h>
#include <stdbool.h>
#include <limits.h>
// Structure to represent a process
struct Process {
int pid; // Process ID
int arrival_time; // Arrival time
int burst_time; // Burst time
};
// Function to find the process with the shortest remaining burst time
int findShortestJob(struct Process processes[], int n, int current_time,int rt[]) {
int shortest_job = -1;
int min_burst_time = INT_MAX;
for (int i = 0; i <n; i++) {
if (processes[i].arrival_time <= current_time && processes[i].burst_time <= min_burst_time && rt[i]!=0) {
min_burst_time = processes[i].burst_time;
shortest_job = i;
}
}
return shortest_job;
}
// Function to calculate waiting time and turnaround time
void calculateTimes(struct Process processes[], int n, int wt[], int tat[]) {
int remaining_time[n];
for (int i = 0; i < n; i++)
remaining_time[i] = processes[i].burst_time;
int completed = 0;
int current_time = 0;
int shortest_jobs[50];
int i=0;
while (completed < n) {
int shortest_job = findShortestJob(processes, n, current_time,remaining_time);
printf("Executing P%d\n",shortest_job);
shortest_jobs[i++]=shortest_job;
if (shortest_job == -1) {
current_time++;
continue;
}
//if (remaining_time[shortest_job] == processes[shortest_job].burst_time)
// {wt[shortest_job] = current_time - processes[shortest_job].arrival_time;}
remaining_time[shortest_job]--;
current_time++;
if (remaining_time[shortest_job] == 0) {
tat[shortest_job] = current_time - processes[shortest_job].arrival_time;
wt[shortest_job]=tat[shortest_job]-processes[shortest_job].burst_time;
completed++;
}
}
}
// Function to calculate average waiting time and turnaround time
void calculateAvgTimes(struct Process processes[], int n) {
int wt[n], tat[n];
calculateTimes(processes, n, wt, tat);
printf("WT \t TAT\n");
for(int i=0;i<n;i++)
printf("%d\t %d\n",wt[i],tat[i]);
float avg_wt = 0, avg_tat = 0;
for (int i = 0; i < n; i++) {
avg_wt += wt[i];
avg_tat += tat[i];
}
printf("Average waiting time = %.2f\n", avg_wt / n);
printf("Average turnaround time = %.2f\n", avg_tat / n);
}
int main() {
int n = 5; // Number of processes
struct Process processes[] = {
{1, 0, 8},
{2, 1, 1},
{3, 2, 3},
{4, 3, 2},
{5, 4, 6}
};
// Calculate average waiting time and turnaround time
calculateAvgTimes(processes, n);
return 0;
}
output:
Executing P0
Executing P1
Executing P2
Executing P3
Executing P3
Executing P2
Executing P2
Executing P4
Executing P4
Executing P4
Executing P4
Executing P4
Executing P4
Executing P0
Executing P0
Executing P0
Executing P0
Executing P0
Executing P0
Executing P0
WT TAT
12 20
0 1
2 5
0 2
3 9
Average waiting time = 3.40
Average turnaround time = 7.40
Comments
Post a Comment