0% found this document useful (0 votes)
15 views

Asssignment Project

The document describes two programs. Program 1 simulates the FCFS and SJF scheduling algorithms. It compares the average waiting times and turnaround times of each algorithm. Program 2 implements the dining philosophers problem using threads and mutex locks to synchronize access to shared resources (forks) and prevent deadlocks.

Uploaded by

dindia871
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
15 views

Asssignment Project

The document describes two programs. Program 1 simulates the FCFS and SJF scheduling algorithms. It compares the average waiting times and turnaround times of each algorithm. Program 2 implements the dining philosophers problem using threads and mutex locks to synchronize access to shared resources (forks) and prevent deadlocks.

Uploaded by

dindia871
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 14

ASSIGNMENT I

Task 1:
Create a program that simulates the FCFS scheduling algorithm and SJF
scheduling in a simple operating system environment to demonstrate its
behaviour and advantages. Provide clear output that shows the execution
order of processes, waiting times, turnaround times, and average statistics.
Compare the response time of each algorithm.

PROGRAM (CPP)

#include <iostream>
#include <vector>
#include <algorithm>

struct Process {
int pid; // Process ID
int arrival_time;
int burst_time;
int completion_time;
int turnaround_time;
int waiting_time;
};

// Function to calculate waiting time for all processes


void calculateWaitingTime(std::vector<Process>& processes) {
processes[0].waiting_time = 0; // First process has 0 waiting time
for (int i = 1; i < processes.size(); ++i) {
processes[i].waiting_time = processes[i - 1].burst_time + processes[i -
1].waiting_time;
}
}

// Function to calculate turnaround time for all processes


void calculateTurnaroundTime(std::vector<Process>& processes) {
for (int i = 0; i < processes.size(); ++i) {
processes[i].turnaround_time = processes[i].burst_time +
processes[i].waiting_time;
}
}

// Function to simulate First Come First Serve (FCFS) scheduling


void simulateFCFS(std::vector<Process>& processes) {
// Sort processes based on arrival time
std::sort(processes.begin(), processes.end(), [](const Process& a, const
Process& b) {
return a.arrival_time < b.arrival_time;
});

calculateWaitingTime(processes);
calculateTurnaroundTime(processes);
}
// Function to simulate Shortest Job First (SJF) scheduling
void simulateSJF(std::vector<Process>& processes) {
// Sort processes based on burst time (shortest job first)
std::sort(processes.begin(), processes.end(), [](const Process& a, const
Process& b) {
return a.burst_time < b.burst_time;
});

calculateWaitingTime(processes);
calculateTurnaroundTime(processes);
}

int main() {
int num_processes;
std::cout << "Enter the number of processes: ";
std::cin >> num_processes;

std::vector<Process> processes(num_processes);

// Input details of each process


for (int i = 0; i < num_processes; ++i) {
std::cout << "Enter arrival time and burst time for process " << i + 1 << ": ";
std::cin >> processes[i].arrival_time >> processes[i].burst_time;
processes[i].pid = i + 1;
}

// Simulate FCFS scheduling


simulateFCFS(processes);

// Display FCFS scheduling results


std::cout << "\nFCFS Scheduling:\n";
std::cout << "Process Execution Order: ";
for (const auto& process : processes) {
std::cout << "P" << process.pid << " ";
}
std::cout << "\n";

// Calculate and display average waiting time and turnaround time


double total_waiting_time = 0, total_turnaround_time = 0;
for (const auto& process : processes) {
total_waiting_time += process.waiting_time;
total_turnaround_time += process.turnaround_time;
}
std::cout << "Average Waiting Time: " << total_waiting_time /
num_processes << "\n";
std::cout << "Average Turnaround Time: " << total_turnaround_time /
num_processes << "\n";

// Simulate SJF scheduling


simulateSJF(processes);

// Display SJF scheduling results


std::cout << "\nSJF Scheduling:\n";
std::cout << "Process Execution Order: ";
for (const auto& process : processes) {
std::cout << "P" << process.pid << " ";
}
std::cout << "\n";

// Calculate and display average waiting time and turnaround time for SJF
total_waiting_time = 0;
total_turnaround_time = 0;
for (const auto& process : processes) {
total_waiting_time += process.waiting_time;
total_turnaround_time += process.turnaround_time;
}
std::cout << "Average Waiting Time: " << total_waiting_time /
num_processes << "\n";
std::cout << "Average Turnaround Time: " << total_turnaround_time /
num_processes << "\n";

return 0;
}
OUTPUT

PROGRAM EXPLANATION
Program Structure:

1. Process Struct: Represents the attributes of a process.


- `pid`: Process ID
- `arrival_time`: Time when the process arrives
- `burst_time`: Time the process needs to execute
- `completion_time`: Time when the process finishes execution
- `turnaround_time`: Time taken for the process to execute (completion time
- arrival time)
- `waiting_time`: Time the process waits before execution

2. Functions
- `calculateWaitingTime`: Calculates waiting time for each process.
- `calculateTurnaroundTime`: Calculates turnaround time for each process.
- `simulateFCFS`: Simulates FCFS scheduling algorithm.
- `simulateSJF`: Simulates SJF scheduling algorithm.

3. Main Function:
- Takes input for the number of processes and their arrival and burst times.
- Simulates FCFS scheduling and displays the order of process execution,
average waiting time, and average turnaround time.
- Simulates SJF scheduling and displays similar results for this algorithm as
well.

Algorithms:

1. FCFS (First Come First Serve):


- Processes are executed in the order they arrive.
- The waiting time for each process is calculated as the sum of the burst times
of all preceding processes.
- Turnaround time is calculated as the burst time plus the waiting time.

2. SJF (Shortest Job First):


- Processes are executed based on their burst times, starting with the
shortest burst time.
- The waiting time for each process is calculated based on the burst time of
shorter jobs that arrive before it.
- Turnaround time is calculated similarly to FCFS, considering the shorter
burst times.

Overall Flow:

1. input
- Number of processes and their arrival times along with burst times are
taken as input.

2. FCFS Simulation
- Processes are sorted based on arrival times.
- FCFS is simulated, and execution order, waiting time, and turnaround time
are calculated and displayed.

3. SJF Simulation
- Processes are sorted based on burst times.
- SJF is simulated, and execution order, waiting time, and turnaround time are
calculated and displayed.

4. Output
- The program outputs the execution order for both algorithms and the
average waiting time and turnaround time for each algorithm.

Presentation Points

1. Introduction
- Explain the purpose of the program: Simulating scheduling algorithms to
manage process execution in an operating system environment.
2. FCFS Explanation
- Detail how FCFS operates by executing processes in the order of their
arrival.
- Highlight the calculation of waiting and turnaround times for each process.

3. SJF Explanation
- Explain SJF, where processes with shorter burst times are prioritized.
- Discuss the impact on waiting and turnaround times.

4. Comparison
- Compare the execution order, waiting time, and turnaround time between
FCFS and SJF.
- Discuss the advantages and disadvantages of each algorithm.

5. Conclusion
- Summarize the behavior and advantages of FCFS and SJF.
- Mention their real-world applications and scenarios where each algorithm
performs well.

Task 2:
Write a program to implement the Dining Philosophers problem using threads
or processes for
synchronization. You need to create a solution that allows multiple
philosophers to share a
limited number of forks (resources) while avoiding deadlock and contention
issues.

Program 2 (CPP)

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

#define NUM_PHILOSOPHERS 5
#define LEFT_FORK (philosopher_id + NUM_PHILOSOPHERS - 1) %
NUM_PHILOSOPHERS
#define RIGHT_FORK (philosopher_id + 1) % NUM_PHILOSOPHERS

pthread_mutex_t forks[NUM_PHILOSOPHERS];
pthread_t philosophers[NUM_PHILOSOPHERS];

void pickup_forks(int philosopher_id) {


pthread_mutex_lock(&forks[LEFT_FORK]);
pthread_mutex_lock(&forks[RIGHT_FORK]);
}

void eat(int philosopher_id) {


printf("Philosopher %d is eating.\n", philosopher_id);
usleep(1000); // Simulating eating
}

void putdown_forks(int philosopher_id) {


pthread_mutex_unlock(&forks[LEFT_FORK]);
pthread_mutex_unlock(&forks[RIGHT_FORK]);
}

void *philosopher_action(void *arg) {


int philosopher_id = *(int *)arg;
while (1) {
printf("Philosopher %d is thinking.\n", philosopher_id);
pickup_forks(philosopher_id);
eat(philosopher_id);
putdown_forks(philosopher_id);
}
}

int main() {
int ids[NUM_PHILOSOPHERS];
int i;

for (i = 0; i < NUM_PHILOSOPHERS; i++) {


pthread_mutex_init(&forks[i], NULL);
}
for (i = 0; i < NUM_PHILOSOPHERS; i++) {
ids[i] = i;
pthread_create(&philosophers[i], NULL, philosopher_action, &ids[i]);
}

for (i = 0; i < NUM_PHILOSOPHERS; i++) {


pthread_join(philosophers[i], NULL);
}

for (i = 0; i < NUM_PHILOSOPHERS; i++) {


pthread_mutex_destroy(&forks[i]);
}

return 0;
}

OUTPUT
PROGRAM EXPLANATION

The Dining Philosophers problem involves synchronization among multiple


threads (representing philosophers) that share a finite set of resources (forks).
In this program, several elements and algorithms are used to address this
problem:

Elements Used:

1. Threads (Philosophers): Each philosopher is represented as a separate


thread in the program.

2. Mutex Locks: Used to represent forks. Mutex locks ensure exclusive access
to the forks, allowing only one philosopher to pick up a fork at a time.

Algorithm Overview:

1. Mutex Locks (Forks): The mutex locks ensure that only one philosopher can
pick up a fork at a time. This prevents multiple philosophers from accessing the
same fork simultaneously, avoiding a race condition.

2. Resource Allocation: Philosophers pick up the left and right forks (mutex
locks) adjacent to them when they want to eat. The algorithm ensures that a
philosopher can only start eating if both the left and right forks are available.
3. Deadlock Avoidance: To avoid deadlock, each philosopher follows a strategy
to pick up forks. If a philosopher cannot acquire both forks, it puts down the
already picked fork and tries again after some time.

4. Simulation of Actions: The actions of thinking, picking up forks, eating, and


putting down forks are simulated with appropriate delays (using `usleep`) to
illustrate the different states of a philosopher's activity.

Workflow:

1. Initialization:Mutex locks are initialized to represent the forks.

2. Threads Creation: Threads (philosophers) are created, each representing a


philosopher, and they execute the `philosopher_action` function in an infinite
loop.

3. Philosopher Actions: Each philosopher performs a sequence of actions:


thinking, picking up forks, eating, and putting down forks. These actions are
synchronized using mutex locks to ensure mutual exclusion.

4. **Thread Joining and Cleanup:** Once all philosophers finish their tasks, the
threads are joined, and mutex locks are destroyed to release system resources.

Conclusion:

This program demonstrates the use of threads, mutex locks, and a


synchronized algorithm to address the Dining Philosophers problem. It ensures
that philosophers can eat without conflicting access to the shared resources
(forks) while preventing deadlock by carefully managing the acquisition of
resources.

You might also like