Practical 4 Os
Practical 4 Os
THEORY :
FCFS (First Come – First Served)
FCFS is a non-preemptive scheduling algorithm where processes are executed in the order
they arrive in the ready queue.
The process that arrives first gets executed first, and no process can preempt the current
running process.
1. Arrival Time (AT): The time at which the process enters the ready queue.
2. Completion Time (CT): The time at which a process finishes execution.
3. Turnaround Time (TAT): It is the total time taken by a process to complete its
execution.
TAT = Completion Time (CT) - Arrival Time (AT)
4. Waiting Time (WT): The time a process spends in the ready queue waiting for its
turn to execute.
WT = Turnaround Time (TAT) - Burst Time (BT)
5. Burst Time (BT): It is the total CPU time required for a process to complete.
➢ Advantages:
1. It is simple and easy to understand.
2. FCFS provides fairness by treating all processes equally and giving them an equal
opportunity to run.
3. FCFS guarantees that every process will eventually get a chance to execute, as long as
the system has enough resources to handle all the processes.
4. FCFS has low scheduling overhead since it does not involve frequent context switches
or complex scheduling decisions.
➢ Disadvantages:
1. The process with less execution time suffers i.e. waiting time is often quite long.
2. Favors CPU Bound process then I/O bound process.
3. This effect results in lower CPU and device utilization.
4. FCFS algorithm is particularly troublesome for multiprogramming systems, where it
is important that each user get a share of the CPU at regular intervals.
➢ Program:
#include<iostream>
#include <algorithm>
using namespace std;
struct Process {
int id, arrivalTime, burstTime, waitingTime, turnaroundTime, completionTime;
};
void calculateFCFS(Process processes[], int n) {
sort(processes, processes + n, [](Process a, Process b)
{ return a.arrivalTime < b.arrivalTime; });
int currentTime = 0;
for (int i = 0; i < n; i++) {
if (currentTime < processes[i].arrivalTime) {
currentTime = processes[i].arrivalTime;
}
processes[i].waitingTime = currentTime - processes[i].arrivalTime;
processes[i].turnaroundTime = processes[i].waitingTime + processes[i].burstTime;
processes[i].completionTime = currentTime + processes[i].burstTime;
currentTime = processes[i].completionTime;
}
}
void displayResults(Process processes[], int n) {
cout << "\n=== FCFS Scheduling Results ===\n";
cout << "Process\tAT\tBT\tCT\tTAT\tWT\n";
double avgWT = 0, avgTAT = 0;
for (int i = 0; i < n; i++) {
cout << "P" << processes[i].id << "\t\t" << processes[i].arrivalTime << "\t"
<< processes[i].burstTime << "\t" << processes[i].completionTime << "\t"
<< processes[i].turnaroundTime << "\t" << processes[i].waitingTime << endl;
avgWT += processes[i].waitingTime;
avgTAT += processes[i].turnaroundTime;
}
cout << "\nAverage Waiting Time: " << avgWT / n << endl;
cout << "Average Turnaround Time: " << avgTAT / n << endl;
}
int main() {
cout<<"Simran Kaur\n CRN: 2315222\n URN: 2302680\n";
int n;
cout << "Enter the number of processes: ";
cin >> n;
Process processes[n];
for (int i = 0; i < n; i++) {
cout << "Enter details for Process " << i + 1 << endl;
processes[i].id = i + 1;
cout << "Arrival Time: ";
cin >> processes[i].arrivalTime;
cout << "Burst Time: ";
cin >> processes[i].burstTime;
}
calculateFCFS(processes, n);
displayResults(processes, n);
return 0;
}
➢ Disadvantages:
1. SJF may cause very long turn-around times or starvation.
2. In SJF job completion time must be known earlier, but sometimes it is hard to
predict.
3. Sometimes, it is complicated to predict the length of the upcoming CPU request.
4. It leads to starvation that does not reduce average turnaround time.
➢ Program:
#include<iostream>
#include <algorithm>
using namespace std;
struct Process {
int id, arrivalTime, burstTime, waitingTime, turnaroundTime, completionTime; };
void calculateSJF(Process processes[], int n) {
sort(processes, processes + n, [](Process a, Process b)
{ if (a.arrivalTime == b.arrivalTime)
return a.burstTime < b.burstTime; return a.arrivalTime < b.arrivalTime; });
int currentTime = 0, completed = 0;
bool visited[n] = {false};
if (index == -1) {
currentTime++; // If no process is ready, move time forward
} else {
processes[index].waitingTime = currentTime - processes[index].arrivalTime;
processes[index].turnaroundTime = processes[index].waitingTime +
processes[index].burstTime;
processes[index].completionTime = currentTime + processes[index].burstTime;
currentTime = processes[index].completionTime;
visited[index] = true;
completed++;
}
}
}
void displayResults(Process processes[], int n) {
cout << "\n=== SJF (Non-Preemptive) Scheduling Results ===\n";
cout << "Process\tAT\tBT\tCT\tTAT\tWT\n";
double avgWT = 0, avgTAT = 0;
for (int i = 0; i < n; i++) {
cout << "P" << processes[i].id << "\t" << processes[i].arrivalTime << "\t"
<< processes[i].burstTime << "\t" << processes[i].completionTime << "\t"
<< processes[i].turnaroundTime << "\t" << processes[i].waitingTime << endl;
avgWT += processes[i].waitingTime;
avgTAT += processes[i].turnaroundTime;
}
cout << "Average Waiting Time: " << avgWT / n << endl;
cout << "Average Turnaround Time: " << avgTAT / n << endl;
}
int main() {
int n;
cout << "Simran Kaur\nURN: 2302680\nCRN:2315222\n";
cout << "Enter number of processes: ";
cin >> n;
Process processes[n];
for (int i = 0; i < n; i++) {
processes[i].id = i + 1;
cout << "Enter Arrival Time for Process " << i + 1 << ": ";
cin >> processes[i].arrivalTime;
cout << "Enter Burst Time for Process " << i + 1 << ": ";
cin >> processes[i].burstTime;
}
calculateSJF(processes, n);
displayResults(processes, n);
return 0;
}
Round Robin
Round Robin Scheduling is a method used by operating systems to manage the execution
time of multiple processes that are competing for CPU attention. It is called "round robin"
because the system rotates through all the processes, allocating each of them a fixed time
slice or "quantum", regardless of their priority.
The primary goal of this scheduling method is to ensure that all processes are given an equal
opportunity to execute, promoting fairness among tasks.
Here's a simple breakdown:
1. Process Arrival: Processes enter the system and are placed in a queue.
2. Time Allocation: Each process is given a certain amount of CPU time, called a
quantum.
3. Execution: The process uses the CPU for the allocated time.
4. Rotation: If the process completes within the time, it leaves the system. If not, it goes
back to the end of the queue.
5. Repeat: The CPU continues to cycle through the queue until all processes are
completed.
➢ Advantages:
1. Fairness: Each process gets an equal share of the CPU.
2. Simplicity: The algorithm is straightforward and easy to implement.
3. Responsiveness: Round Robin can handle multiple processes without significant
delays, making it ideal for time-sharing systems.
➢ Disadvantages:
1. Overhead: Switching between processes can lead to high overhead, especially if the
quantum is too small.
2. Underutilization: If the quantum is too large, it can cause the CPU to feel
unresponsive as it waits for a process to finish its time.
➢ Program:
#include<iostream>
using namespace std;
void findWaitingTime(int processes[], int n, int bt[], int wt[], int quantum) {
int rem_bt[n];
for (int i = 0; i < n; i++)
rem_bt[i] = bt[i];
int t = 0;
while (1)
{
bool done = true;
for (int i = 0; i < n; i++)
{
if (rem_bt[i] > 0)
{
done = false;
if (rem_bt[i] > quantum)
{
t += quantum;
rem_bt[i] -= quantum;
}
else
{
t += rem_bt[i];
wt[i] = t - bt[i];
rem_bt[i] = 0;
}
}
}
if (done == true)
break;
}
}
void findTurnAroundTime(int processes[], int n, int bt[], int wt[], int tat[]) {
for (int i = 0; i < n; i++)
tat[i] = bt[i] + wt[i];
}
void findavgTime(int processes[], int n, int bt[], int quantum) {
int wt[n], tat[n], total_wt = 0, total_tat = 0;
findWaitingTime(processes, n, bt, wt, quantum);
findTurnAroundTime(processes, n, bt, wt, tat);
cout << "PN\t BT\t WT\t TAT\n";
for (int i = 0; i < n; i++)
{
total_wt += wt[i];
total_tat += tat[i];
cout << i + 1 << "\t" << bt[i] << "\t" << wt[i] << "\t" << tat[i] << endl;
}
cout << "Average waiting time = " << (float)total_wt / (float)n << endl;
cout << "Average turn around time = " << (float)total_tat / (float)n << endl;
}
int main() {
cout << "Simran Kaur\nURN: 2302680\nCRN:2315222\n";
int n; cout << "Enter number of processes: "; cin >> n;
int processes[n], burst_time[n];
cout << "Enter burst times for " << n << " processes: ";
for (int i = 0; i < n; i++)
cin >> burst_time[i];
int quantum;
cout << "Enter time quantum: ";
cin >> quantum;
Priority
Priority scheduling is one of the most common scheduling algorithms used by the operating
system to schedule processes based on their priority. Each process is assigned a priority. The
process with the highest priority is to be executed first and so on.
Processes with the same priority are executed on a first-come first served basis. Priority can
be decided based on memory requirements, time requirements or any other resource
requirement. Also priority can be decided on the ratio of average I/O to average CPU burst
time.
➢ Advantages:
1. Flexibility: Allows prioritization based on task importance.
2. Performance: Optimizes execution for critical tasks.
3. Simplicity: Easy to implement and understand.
4. Resource Efficiency: Allocates resources based on process needs.
➢ Disadvantages:
1. Starvation: Low-priority processes may never execute.
2. Overhead: Managing priorities can add system complexity.
3. Preemption Overhead: Frequent context switching can slow down the system.
4. Priority Assignment: Difficult to assign accurate priorities for optimal performance.
➢ Program:
#include<iostream>
#include <algorithm>
using namespace std;
struct process {
int at, bt, pr, pno;
};
bool comp(process a, process b) {
if (a.at == b.at)
return a.pr < b.pr;
else return a.at < b.at;
}
void get_wt_time(int wt[], process proc[], int totalprocess) {
int service[50];
service[0] = proc[0].at; wt[0] = 0;
for (int i = 1; i < totalprocess; i++) {
service[i] = proc[i-1].bt + service[i-1];
wt[i] = service[i] - proc[i].at;
if (wt[i] < 0) {
wt[i] = 0;
}
}}
void get_tat_time(int tat[], int wt[], process proc[], int totalprocess) {
for (int i = 0; i < totalprocess; i++)
{ tat[i] = proc[i].bt + wt[i]; }
}
void findgc(process proc[], int totalprocess) {
int wt[50], tat[50];
double wavg = 0, tavg = 0;
get_wt_time(wt, proc, totalprocess);
get_tat_time(tat, wt, proc, totalprocess);
int stime[50], ctime[50];
stime[0] = proc[0].at; ctime[0] = stime[0] + tat[0];
for (int i = 1; i < totalprocess; i++) {
stime[i] = ctime[i-1];
ctime[i] = stime[i] + tat[i] - wt[i];
}
cout << "No.\tStart\tComplete\tTurnAround\tWaiting\n";
for (int i = 0; i < totalprocess; i++) {
wavg += wt[i];
tavg += tat[i];
cout << proc[i].pno << "\t\t" << stime[i] << "\t\t" << ctime[i] << "\t\t" << tat[i] << "\t\t\t" <<
wt[i] << endl;
}
cout << "Average waiting time is: " << wavg / (float)totalprocess << endl;
cout << "Average turnaround time: " << tavg / (float)totalprocess << endl;
}
int main() {
cout << "Simran Kaur\nURN: 2302680\nCRN:2315222\n";
int totalprocess;
cout << "Enter the number of processes: ";
cin >> totalprocess;
process proc[totalprocess];
cout << "Enter the arrival times, burst times, and priorities of the processes:\n";
for (int i = 0; i < totalprocess; i++) {
cout << "For Process " << i + 1 << ":\n"; proc[i].pno = i + 1;
cout << "Arrival Time: ";
cin >> proc[i].at;
cout << "Burst Time: ";
cin >> proc[i].bt; cout << "Priority: ";
cin >> proc[i].pr;
}
sort(proc, proc + totalprocess, comp);
findgc(proc, totalprocess);
return 0;
}