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

OS Practical File

Uploaded by

jagrit.jain.ug22
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
15 views

OS Practical File

Uploaded by

jagrit.jain.ug22
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 47

NETAJI SUBHAS UNIVERSITY OF

TECHNOLOGY
(EAST CAMPUS)
Geeta Colony, New Delhi-110031

OPERATING SYSTEMS
Course Code: CBCPC09
PRACTICAL FILE

Submitted By: Bhaumik Solanki


Submitted To: Manoj Kumar
Roll Number: 2022UCB6013
Branch: CSDA
Section: 1(4th Sem)
INDEX

S. No. Experiments Page No. Date Signature


1 Write a program to implement process creation and 1
termination for operating system (fork, wait, signal, exit,
etc.).
2 Write a program to implement threads. 3

3a Write a program to implement CPU scheduling 5


algorithm for FCFS.
3b Write a program to implement CPU scheduling 7
algorithm for SJF.
3c Write a program to implement CPU scheduling 10
algorithm for Round Robin.
3d Write a program to implement CPU scheduling 13
algorithm for Preemptive Priority Scheduling.
4 Write a program to implement inter process 16
communication.
5 Write a program to implement critical section problem. 18

6a Write a program to implement producer-consumer 20


problem using bounded buffer.
6b Write a program to implement producer-consumer 23
problem using unbounded buffer.
7a Write a program to implement readers-writers problem 27
using semaphores.
7b Write a program to implement dining philosophers 30
problem using semaphores.
8 Write a program to implement banker’s algorithm. 32

9a Write a program to implement LRU page replacement 35


algorithm.
9b Write a program to implement LRU-approximation page 38
replacement algorithm.
9c Write a program to implement FIFO page replacement 41
algorithm.
9d Write a program to implement optimal page 43
replacement algorithm.
Experiment-1
Aim: Write a program to implement process creation and termination for operating system (fork, wait,
signal, exit, etc.).

Algorithm:
1. The main function begins by forking a child process using the ‘fork()’ function. This creates a new
process.
2. The ‘fork()’ function returns the process ID (PID) of the child process to the parent and 0 to the child
process.
3. If ‘fork()’ returns -1, it indicates that the fork failed.
4. If ‘fork()’ returns 0, it means we are in the child process. In the child process, we call ‘childProcess()’
which performs some tasks specific to the child process and then exits using ‘exit()’.
5. If ‘fork()’ returns a positive value, it means we are in the parent process. In the parent process, we
call ‘parentProcess()’, which waits for the child process to terminate using ‘wait()’.
6. Once the child process terminates, the parent process resumes execution after the ‘wait()’ call. It
prints a message indicating that the child process has terminated.
7. Both the parent and child processes reach the end of their execution and exit.

Code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>

void childProcess() {
printf("Child process ID: %d\n", getpid());
sleep(3); // Simulate some work
printf("Child process exiting...\n");
exit(0);
}

void parentProcess(pid_t child_pid) {


printf("Parent process ID: %d\n", getpid());
printf("Waiting for child process to finish...\n");
wait(NULL); // Wait for any child process to terminate
printf("Child process terminated.\n");
}

int main() {
pid_t child_pid;

// Fork a child process


child_pid = fork();

if (child_pid == -1) {
perror("Fork failed");
exit(1);
} else if (child_pid == 0) {
// Child process
childProcess();
} else {
// Parent process
parentProcess(child_pid);

1
}

printf("Exiting...\n");

return 0;
}

Output:

2
Experiment-2
Aim: Write a program to implement threads.

Algorithm:
1. The program begins by defining the ‘threadFunction’ function, which serves as the entry point for
each thread. This function prints a message identifying the thread by its ID (‘tid’), which is passed as
an argument.
2. In the ‘main’ function, an array of ‘pthread_t’ objects is declared to hold thread IDs.
3. A loop is used to create and start multiple threads. Inside the loop:
a. Each thread is created using ‘pthread_create()’, passing the thread ID, thread attributes
(NULL for default), the function to be executed (‘threadFunction’), and an argument (‘t’).
b. The loop iterates over the range of thread IDs (0 to ‘NUM_THREADS - 1’).
4. After creating all threads, another loop (‘pthread_join’) is used to wait for each thread to finish
execution. This ensures that the main thread waits for all threads to complete before proceeding.
5. Finally, the program prints a message indicating that all threads have completed and exits.

Code:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

#define NUM_THREADS 5

void *threadFunction(void *threadID) {


long tid;
tid = (long)threadID;
printf("Hello World! It's me, thread #%ld!\n", tid);
pthread_exit(NULL);
}

int main() {
pthread_t threads[NUM_THREADS];
int rc;
long t;

for (t = 0; t < NUM_THREADS; t++) {


printf("Creating thread %ld\n", t);
rc = pthread_create(&threads[t], NULL, threadFunction, (void *)t);
if (rc) {
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}

// Wait for all threads to finish


for (t = 0; t < NUM_THREADS; t++) {
pthread_join(threads[t], NULL);
}

printf("All threads have completed.\n");


pthread_exit(NULL);
}

3
Output:

4
Experiment-3a
Aim: Write a program to implement CPU scheduling algorithm for FCFS.

Algorithm:
1. Define a structure ‘Process’ to represent each process, containing attributes such as process ID,
arrival time, burst time, and completion time.
2. Implement the ‘computeCompletionTime’ function to calculate the completion time for each
process based on the FCFS algorithm. The algorithm proceeds as follows:
a. Initialize ‘currentTime’ to 0.
b. Iterate through each process:
i. If the current time is less than the arrival time of the process, set the current time to
the arrival time of the process.
ii. Calculate the completion time of the process by adding its burst time to the current
time.
iii. Update the current time to the completion time of the process.
3. Implement the ‘calculateAverageTurnaroundTime’ function to compute the average turnaround
time of all processes.
4. In the ‘main’ function:
a. Define an array of ‘Process’ structures representing the processes.
b. Calculate the completion time of each process using the ‘computeCompletionTime’
function.
c. Output the completion time of each process.
d. Calculate and output the average turnaround time of all processes.

Code:
#include <stdio.h>

// Process structure
typedef struct {
int processID;
int arrivalTime;
int burstTime;
int completionTime;
} Process;

// Function to compute completion time for each process using FCFS algorithm
void computeCompletionTime(Process processes[], int n) {
int currentTime = 0;

for (int i = 0; i < n; i++) {


// If the process has not arrived yet, wait until it arrives
if (currentTime < processes[i].arrivalTime)
currentTime = processes[i].arrivalTime;

// Calculate completion time


processes[i].completionTime = currentTime + processes[i].burstTime;

// Update current time


currentTime = processes[i].completionTime;
}
}

// Function to calculate average turnaround time

5
float calculateAverageTurnaroundTime(Process processes[], int n) {
float totalTurnaroundTime = 0;
for (int i = 0; i < n; i++) {
totalTurnaroundTime += (processes[i].completionTime - processes[i].arrivalTime);
}
return totalTurnaroundTime / n;
}

int main() {
// Define processes
Process processes[] = {
{1, 0, 6, 0},
{2, 2, 4, 0},
{3, 4, 8, 0},
{4, 6, 5, 0},
{5, 8, 3, 0}
};

int n = sizeof(processes) / sizeof(processes[0]);

// Calculate completion time using FCFS algorithm


computeCompletionTime(processes, n);

// Output the completion time of each process


printf("Process\tCompletion Time\n");
for (int i = 0; i < n; i++) {
printf("%d\t%d\n", processes[i].processID, processes[i].completionTime);
}

// Calculate and output average turnaround time


float avgTurnaroundTime = calculateAverageTurnaroundTime(processes, n);
printf("Average Turnaround Time: %.2f\n", avgTurnaroundTime);

return 0;
}

Output:

6
Experiment-3b
Aim: Write a program to implement CPU scheduling algorithm for SJF.

Algorithm:
1. Define a structure ‘Process’ to represent each process, containing attributes such as process ID,
arrival time, burst time, completion time, and waiting time.
2. Implement the ‘computeCompletionTime’ function to calculate the completion time for each
process using the SJF algorithm. The algorithm proceeds as follows:
a. Initialize ‘currentTime’ to 0 and ‘totalBurstTime’ to the sum of burst times of all processes.
b. Initialize waiting time for the first process to 0.
c. Iterate until all processes are executed:
i. Find the process with the minimum burst time among the arrived processes.
ii. Update the current time and total burst time.
iii. Calculate completion time and waiting time for the selected process.
iv. Set burst time to 0 for the completed process.
3. Implement the ‘calculateAverageWaitingTime’ function to compute the average waiting time of all
processes.
4. In the ‘main’ function:
a. Define an array of ‘Process’ structures representing the processes.
b. Calculate the completion time of each process using the ‘computeCompletionTime’
function.
c. Output the completion time and waiting time of each process.
d. Calculate and output the average waiting time of all processes.

Code:
#include <stdio.h>

// Process structure
typedef struct {
int processID;
int arrivalTime;
int burstTime;
int completionTime;
int waitingTime;
} Process;

// Function to compute completion time for each process using SJF algorithm
void computeCompletionTime(Process processes[], int n) {
int currentTime = 0;
int totalBurstTime = 0;
int minIndex, minBurstTime;

// Initialize waiting time for the first process


processes[0].waitingTime = 0;

// Calculate total burst time


for (int i = 0; i < n; i++) {
totalBurstTime += processes[i].burstTime;
}

// Iterate until all processes are executed


while (totalBurstTime > 0) {
minBurstTime = __INT_MAX__;

7
// Find the process with the minimum burst time among arrived processes
for (int i = 0; i < n; i++) {
if (processes[i].arrivalTime <= currentTime && processes[i].burstTime <
minBurstTime && processes[i].burstTime > 0) {
minBurstTime = processes[i].burstTime;
minIndex = i;
}
}

// Update current time


currentTime += minBurstTime;
totalBurstTime -= minBurstTime;

// Calculate completion time and waiting time


processes[minIndex].completionTime = currentTime;
processes[minIndex].waitingTime = currentTime - processes[minIndex].arrivalTime -
processes[minIndex].burstTime;

// Set burst time to 0 for the completed process


processes[minIndex].burstTime = 0;
}
}

// Function to calculate average waiting time


float calculateAverageWaitingTime(Process processes[], int n) {
float totalWaitingTime = 0;
for (int i = 0; i < n; i++) {
totalWaitingTime += processes[i].waitingTime;
}
return totalWaitingTime / n;
}

int main() {
// Define processes
Process processes[] = {
{1, 0, 6, 0, 0},
{2, 2, 4, 0, 0},
{3, 4, 8, 0, 0},
{4, 6, 5, 0, 0},
{5, 8, 3, 0, 0}
};

int n = sizeof(processes) / sizeof(processes[0]);

// Calculate completion time using SJF algorithm


computeCompletionTime(processes, n);
// Output the completion time and waiting time of each process
printf("Process\tCompletion Time\tWaiting Time\n");
for (int i = 0; i < n; i++) {
printf("%d\t%d\t\t%d\n", processes[i].processID, processes[i].completionTime,
processes[i].waitingTime);
}
// Calculate and output average waiting time
float avgWaitingTime = calculateAverageWaitingTime(processes, n);
printf("Average Waiting Time: %.2f\n", avgWaitingTime);

return 0;
}

8
Output:

9
Experiment-3c
Aim: Write a program to implement CPU scheduling algorithm for Round Robin.

Algorithm:
1. Define a structure ‘Process’ to represent each process, containing attributes such as process ID,
arrival time, burst time, remaining time, completion time, turnaround time, and waiting time.
2. Implement the ‘roundRobin’ function to simulate the Round Robin scheduling algorithm. The
algorithm proceeds as follows:
a. Iterate until all processes are executed:
i. Iterate over each process:
1. If the process has arrived and has remaining burst time:
a. Execute the process for a quantum of time (defined by ‘QUANTUM’)
or for its remaining burst time, whichever is smaller.
b. Update the current time and remaining time of the process.
c. If the process finishes execution (remaining time becomes 0), update
its completion time, turnaround time, and waiting time.
3. Implement the ‘calculateAverageTimes’ function to calculate the average turnaround time and
waiting time of all processes.
4. In the ‘main’ function:
a. Define an array of ‘Process’ structures representing the processes.
b. Perform Round Robin scheduling using the ‘roundRobin’ function.
c. Calculate average turnaround time and waiting time using the ‘calculateAverageTimes’
function.
d. Output the completion time, turnaround time, and waiting time of each process, as well as
the average turnaround time and waiting time.

Code:
#include <stdio.h>
#include <stdlib.h>

#define QUANTUM 2

// Process structure
typedef struct {
int processID;
int arrivalTime;
int burstTime;
int remainingTime;
int completionTime;
int turnaroundTime;
int waitingTime;
} Process;

// Function to simulate Round Robin scheduling


void roundRobin(Process processes[], int n) {
int currentTime = 0;
int remainingProcesses = n;

// Iterate until all processes are executed


while (remainingProcesses > 0) {
// Iterate over each process
for (int i = 0; i < n; i++) {
// Execute the process if it has arrived and has remaining burst time
10
if (processes[i].arrivalTime <= currentTime && processes[i].remainingTime > 0)
{
// Execute process for the quantum or remaining burst time, whichever is
smaller
int executeTime = (processes[i].remainingTime < QUANTUM) ?
processes[i].remainingTime : QUANTUM;
currentTime += executeTime;
processes[i].remainingTime -= executeTime;

// Update completion time if process finishes execution


if (processes[i].remainingTime == 0) {
remainingProcesses--;
processes[i].completionTime = currentTime;
processes[i].turnaroundTime = processes[i].completionTime -
processes[i].arrivalTime;
processes[i].waitingTime = processes[i].turnaroundTime -
processes[i].burstTime;
}
}
}
}
}

// Function to calculate average turnaround time and waiting time


void calculateAverageTimes(Process processes[], int n, float *avgTurnaroundTime, float
*avgWaitingTime) {
float totalTurnaroundTime = 0, totalWaitingTime = 0;
for (int i = 0; i < n; i++) {
totalTurnaroundTime += processes[i].turnaroundTime;
totalWaitingTime += processes[i].waitingTime;
}
*avgTurnaroundTime = totalTurnaroundTime / n;
*avgWaitingTime = totalWaitingTime / n;
}

int main() {
// Define processes
Process processes[] = {
{1, 0, 6, 6, 0, 0, 0},
{2, 2, 4, 4, 0, 0, 0},
{3, 4, 8, 8, 0, 0, 0},
{4, 6, 5, 5, 0, 0, 0},
{5, 8, 3, 3, 0, 0, 0}
};

int n = sizeof(processes) / sizeof(processes[0]);

// Perform Round Robin scheduling


roundRobin(processes, n);

// Calculate average turnaround time and waiting time


float avgTurnaroundTime, avgWaitingTime;
calculateAverageTimes(processes, n, &avgTurnaroundTime, &avgWaitingTime);

// Output results
printf("Process\tCompletion Time\tTurnaround Time\tWaiting Time\n");
for (int i = 0; i < n; i++) {
printf("%d\t%d\t\t%d\t\t%d\n", processes[i].processID,
processes[i].completionTime,
processes[i].turnaroundTime, processes[i].waitingTime);
11
}
printf("Average Turnaround Time: %.2f\n", avgTurnaroundTime);
printf("Average Waiting Time: %.2f\n", avgWaitingTime);

return 0;
}

Output:

12
Experiment-3d
Aim: Write a program to implement CPU scheduling algorithm for Preemptive Priority Scheduling.

Algorithm:
1. Define a structure ‘Process’ to represent each process, containing attributes such as process ID,
arrival time, burst time, priority, remaining time, completion time, turnaround time, and waiting
time.
2. Implement the ‘preemptivePriority’ function to simulate the Preemptive Priority scheduling
algorithm. The algorithm proceeds as follows:
a. Iterate until all processes are executed:
i. Find the process with the highest priority among the arrived processes.
ii. Execute the process for one time unit.
iii. If the process finishes execution, update its completion time and calculate its
turnaround/waiting time.
3. Implement the ‘calculateAverageTimes’ function to calculate the average turnaround time and
waiting time of all processes.
4. In the ‘main’ function:
a. Define an array of ‘Process’ structures representing the processes.
b. Perform Preemptive Priority scheduling using the ‘preemptivePriority’ function.
c. Calculate average turnaround time and waiting time using the ‘calculateAverageTimes’
function.
d. Output the completion time, turnaround time, and waiting time of each process, as well as
the average turnaround time and waiting time.

Code:
#include <stdio.h>
#include <stdlib.h>

// Process structure
typedef struct {
int processID;
int arrivalTime;
int burstTime;
int priority;
int remainingTime;
int completionTime;
int turnaroundTime;
int waitingTime;
} Process;

// Function to simulate Preemptive Priority scheduling


void preemptivePriority(Process processes[], int n) {
int currentTime = 0;
int remainingProcesses = n;
int highestPriorityIndex, highestPriority;

// Iterate until all processes are executed


while (remainingProcesses > 0) {
highestPriority = -1;

// Find the process with the highest priority among arrived processes
for (int i = 0; i < n; i++) {

13
if (processes[i].arrivalTime <= currentTime && processes[i].remainingTime > 0)
{
if (highestPriority == -1 || processes[i].priority < highestPriority) {
highestPriority = processes[i].priority;
highestPriorityIndex = i;
}
}
}

// Execute the process with the highest priority for one time unit
currentTime++;
processes[highestPriorityIndex].remainingTime--;

// If the process finishes execution, update completion time and calculate


turnaround/waiting time
if (processes[highestPriorityIndex].remainingTime == 0) {
remainingProcesses--;
processes[highestPriorityIndex].completionTime = currentTime;
processes[highestPriorityIndex].turnaroundTime =
processes[highestPriorityIndex].completionTime -
processes[highestPriorityIndex].arrivalTime;
processes[highestPriorityIndex].waitingTime =
processes[highestPriorityIndex].turnaroundTime -
processes[highestPriorityIndex].burstTime;
}
}
}

// Function to calculate average turnaround time and waiting time


void calculateAverageTimes(Process processes[], int n, float *avgTurnaroundTime, float
*avgWaitingTime) {
float totalTurnaroundTime = 0, totalWaitingTime = 0;
for (int i = 0; i < n; i++) {
totalTurnaroundTime += processes[i].turnaroundTime;
totalWaitingTime += processes[i].waitingTime;
}
*avgTurnaroundTime = totalTurnaroundTime / n;
*avgWaitingTime = totalWaitingTime / n;
}

int main() {
// Define processes
Process processes[] = {
{1, 0, 6, 2, 6, 0, 0, 0},
{2, 2, 4, 1, 4, 0, 0, 0},
{3, 4, 8, 3, 8, 0, 0, 0},
{4, 6, 5, 4, 5, 0, 0, 0},
{5, 8, 3, 5, 3, 0, 0, 0}
};

int n = sizeof(processes) / sizeof(processes[0]);

// Perform Preemptive Priority scheduling


preemptivePriority(processes, n);

// Calculate average turnaround time and waiting time


float avgTurnaroundTime, avgWaitingTime;
calculateAverageTimes(processes, n, &avgTurnaroundTime, &avgWaitingTime);

// Output results
14
printf("Process\tCompletion Time\tTurnaround Time\tWaiting Time\n");
for (int i = 0; i < n; i++) {
printf("%d\t%d\t\t%d\t\t%d\n", processes[i].processID,
processes[i].completionTime,
processes[i].turnaroundTime, processes[i].waitingTime);
}
printf("Average Turnaround Time: %.2f\n", avgTurnaroundTime);
printf("Average Waiting Time: %.2f\n", avgWaitingTime);

return 0;
}

Output:

15
Experiment-4
Aim: Write a program to implement inter process communication.

Algorithm:
1. Create a pipe using the ‘pipe()’ system call. This creates a unidirectional communication channel
with two file descriptors: one for reading and one for writing.
2. Fork a child process using the ‘fork()’ system call. This creates a copy of the parent process.
3. In the parent process:
a. Close the write end of the pipe, as it will only read from the pipe.
b. Read from the pipe using the ‘read()’ system call.
c. Print the received message from the child process.
d. Close the read end of the pipe.
4. In the child process:
a. Close the read end of the pipe, as it will only write to the pipe.
b. Write to the pipe using the ‘write()’ system call.
c. Close the write end of the pipe.
5. Both parent and child processes terminate, and the communication is completed.

Code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

#define READ_END 0
#define WRITE_END 1

int main() {
int pipefd[2];
pid_t pid;
char messageParent[] = "Hello Child!";
char messageChild[] = "Hi Parent!";
char buffer[100];

// Create pipe
if (pipe(pipefd) == -1) {
perror("Pipe creation failed");
exit(EXIT_FAILURE);
}

// Fork a child process


pid = fork();

if (pid < 0) {
perror("Fork failed");
exit(EXIT_FAILURE);
}

if (pid > 0) { // Parent process


// Close the unused write end of the pipe
close(pipefd[WRITE_END]);

// Read from the pipe


read(pipefd[READ_END], buffer, sizeof(buffer));

16
printf("Parent received message from child: %s\n", buffer);

// Close the read end of the pipe


close(pipefd[READ_END]);
} else { // Child process
// Close the unused read end of the pipe
close(pipefd[READ_END]);

// Write to the pipe


write(pipefd[WRITE_END], messageParent, sizeof(messageParent));

// Close the write end of the pipe


close(pipefd[WRITE_END]);
}

return 0;
}

Output:

17
Experiment-5
Aim: Write a program to implement critical section problem.

Algorithm:
1. Define a global variable ‘counter’ to represent the shared resource.
2. Initialize a mutex lock using ‘pthread_mutex_init()’ function.
3. Create multiple threads, each representing a process. Each thread will execute the ‘criticalSection’
function.
4. In the ‘criticalSection’ function:
a. Entry section: Acquire the mutex lock using ‘pthread_mutex_lock()’ function.
b. Critical section: Access the shared resource (increment the counter).
c. Exit section: Release the mutex lock using ‘pthread_mutex_unlock()’ function.
d. Non-critical section: Perform other tasks.
5. After creating all threads, wait for each thread to finish execution using ‘pthread_join()’ function.
6. Destroy the mutex lock using ‘pthread_mutex_destroy()’ function.
7. Print the final value of the shared resource (‘counter’).

Code:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

#define NUM_THREADS 5

// Global variables
int counter = 0;
pthread_mutex_t mutex;

// Function representing the critical section


void *criticalSection(void *threadID) {
long tid;
tid = (long)threadID;

// Entry section: Acquire mutex lock


pthread_mutex_lock(&mutex);

// Critical section: Access shared resource (increment counter)


printf("Thread #%ld is in critical section\n", tid);
counter++;

// Exit section: Release mutex lock


pthread_mutex_unlock(&mutex);

// Non-critical section: Perform other tasks


printf("Thread #%ld is in non-critical section\n", tid);

pthread_exit(NULL);
}

int main() {
pthread_t threads[NUM_THREADS];
int rc;
long t;

// Initialize mutex lock


18
if (pthread_mutex_init(&mutex, NULL) != 0) {
printf("Mutex initialization failed\n");
return 1;
}

// Create threads
for (t = 0; t < NUM_THREADS; t++) {
printf("Creating thread %ld\n", t);
rc = pthread_create(&threads[t], NULL, criticalSection, (void *)t);
if (rc) {
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}

// Wait for all threads to finish


for (t = 0; t < NUM_THREADS; t++) {
pthread_join(threads[t], NULL);
}

// Destroy mutex lock


pthread_mutex_destroy(&mutex);

printf("Counter value after execution: %d\n", counter);

return 0;
}

Output:

19
Experiment-6a
Aim: Write a program to implement producer-consumer problem using bounded buffer.

Algorithm:
1. Define a fixed-size buffer and the necessary synchronization primitives: semaphores (‘empty’ and
‘full’) to track empty and filled buffer slots respectively, and a mutex to protect buffer access.
2. Implement the ‘produce()’ function to add an item to the buffer and the ‘consume()’ function to
remove an item from the buffer.
3. Implement producer and consumer thread functions (‘producer()’ and ‘consumer()’ respectively).
4. In the ‘producer()’ function:
a. Generate a random item.
b. Wait for an empty buffer slot (‘sem_wait(&empty)’).
c. Lock the mutex (‘pthread_mutex_lock(&mutex)’) before accessing the buffer.
d. Produce the item and add it to the buffer using the ‘produce()’ function.
e. Unlock the mutex (‘pthread_mutex_unlock(&mutex)’) after accessing the buffer.
f. Signal that the buffer is no longer empty (‘sem_post(&full)’).
g. Sleep for a random time.
5. In the ‘consumer()’ function:
a. Wait for a filled buffer slot (‘sem_wait(&full)’).
b. Lock the mutex (‘pthread_mutex_lock(&mutex)’) before accessing the buffer.
c. Consume an item from the buffer using the ‘consume()’ function.
d. Unlock the mutex (‘pthread_mutex_unlock(&mutex)’) after accessing the buffer.
e. Signal that the buffer is no longer full (‘sem_post(&empty)’).
f. Sleep for a random time.
6. In the ‘main()’ function:
a. Initialize semaphores and mutex.
b. Create producer and consumer threads.
c. Join producer and consumer threads.
d. Destroy semaphores and mutex.

Code:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#define BUFFER_SIZE 5 // Size of the bounded buffer
#define NUM_PRODUCERS 2 // Number of producer threads
#define NUM_CONSUMERS 2 // Number of consumer threads
#define NUM_ITEMS 10 // Number of items to be produced/consumed
int buffer[BUFFER_SIZE]; // Bounded buffer
int in = 0; // Index to insert into buffer
int out = 0; // Index to remove from buffer
// Semaphore declarations
sem_t empty; // Counts empty slots in the buffer
sem_t full; // Counts filled slots in the buffer
sem_t mutex; // Ensures mutual exclusion for buffer access
// Function prototypes
void *producer(void *arg);
void *consumer(void *arg);
void insert_item(int item);
int remove_item();
20
int main() {
pthread_t producer_threads[NUM_PRODUCERS];
pthread_t consumer_threads[NUM_CONSUMERS];
// Initialize semaphores
sem_init(&empty, 0, BUFFER_SIZE);
sem_init(&full, 0, 0);
sem_init(&mutex, 0, 1);
// Create producer threads
for (int i = 0; i < NUM_PRODUCERS; i++) {
pthread_create(&producer_threads[i], NULL, producer, NULL);
}
// Create consumer threads
for (int i = 0; i < NUM_CONSUMERS; i++) {
pthread_create(&consumer_threads[i], NULL, consumer, NULL);
}
// Join producer threads
for (int i = 0; i < NUM_PRODUCERS; i++) {
pthread_join(producer_threads[i], NULL);
}
// Join consumer threads
for (int i = 0; i < NUM_CONSUMERS; i++) {
pthread_join(consumer_threads[i], NULL);
}
// Destroy semaphores
sem_destroy(&empty);
sem_destroy(&full);
sem_destroy(&mutex);
return 0;
}
void *producer(void *arg) {
int produced_items = 0;
while (produced_items < NUM_ITEMS) {
// Produce item
int item = rand() % 100;
// Wait for an empty slot in the buffer
sem_wait(&empty);
// Acquire mutex to access buffer
sem_wait(&mutex);
// Insert item into buffer
insert_item(item);
printf("Producer produced item: %d\n", item);
// Release mutex and signal that buffer is full
sem_post(&mutex);
sem_post(&full);
produced_items++;
}
pthread_exit(NULL);
}
void *consumer(void *arg) {
int consumed_items = 0;
while (consumed_items < NUM_ITEMS) {
// Wait for a full slot in the buffer
sem_wait(&full);
// Acquire mutex to access buffer
sem_wait(&mutex);
// Remove item from buffer
int item = remove_item();
printf("Consumer consumed item: %d\n", item);

21
// Release mutex and signal that buffer is empty
sem_post(&mutex);
sem_post(&empty);
consumed_items++;
}
pthread_exit(NULL);
}
void insert_item(int item) {
buffer[in] = item;
in = (in + 1) % BUFFER_SIZE;
}
int remove_item() {
int item = buffer[out];
out = (out + 1) % BUFFER_SIZE;
return item;
}

Output:

22
Experiment-6b
Aim: Write a program to implement producer-consumer problem using unbounded buffer.

Algorithm:
1. Define a node structure for the linked list queue (‘Node’) and a structure for the queue (‘Queue’).
2. Implement queue operations: ‘initQueue()’ to initialize the queue, ‘enqueue()’ to add an item to the
queue, and ‘dequeue()’ to remove an item from the queue.
3. Implement producer and consumer thread functions (‘producer()’ and ‘consumer()’ respectively).
4. In the ‘producer()’ function:
a. Generate an item.
b. Enqueue the item using the ‘enqueue()’ function.
c. Print a message indicating that an item has been produced.
d. Sleep for a random time.
5. In the ‘consumer()’ function:
a. Dequeue an item using the ‘dequeue()’ function.
b. Print a message indicating that an item has been consumed.
c. Sleep for a random time.
6. In the ‘main()’ function:
a. Initialize the queue using ‘initQueue()’.
b. Create producer and consumer threads using ‘pthread_create()’.
c. Join producer and consumer threads using ‘pthread_join()’.
d. Destroy the mutex and semaphore using ‘pthread_mutex_destroy()’ and ‘sem_destroy()’
respectively.

Code:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#include <stdbool.h>

#define BUFFER_SIZE 5 // Size of the unbounded buffer

// Structure to represent a node in the linked list


typedef struct Node {
int data;
struct Node* next;
} Node;

// Structure to represent the unbounded buffer


typedef struct {
Node* head;
Node* tail;
sem_t mutex;
sem_t items;
bool end_of_production;
} Buffer;

// Function prototypes
void buffer_init(Buffer* buffer);
void buffer_insert(Buffer* buffer, int data);
int buffer_remove(Buffer* buffer);

23
void buffer_destroy(Buffer* buffer);
void* producer(void* arg);
void* consumer(void* arg);

int main() {
Buffer buffer;
buffer_init(&buffer);

pthread_t producer_thread, consumer_thread;

// Create producer thread


pthread_create(&producer_thread, NULL, producer, (void*)&buffer);

// Create consumer thread


pthread_create(&consumer_thread, NULL, consumer, (void*)&buffer);

// Join producer thread


pthread_join(producer_thread, NULL);

// Set end of production flag and signal the consumer to wake up


buffer.end_of_production = true;
sem_post(&buffer.items);

// Join consumer thread


pthread_join(consumer_thread, NULL);

buffer_destroy(&buffer);

return 0;
}

// Initialize the unbounded buffer


void buffer_init(Buffer* buffer) {
buffer->head = NULL;
buffer->tail = NULL;
sem_init(&buffer->mutex, 0, 1);
sem_init(&buffer->items, 0, 0);
buffer->end_of_production = false;
}

// Insert an item into the buffer


void buffer_insert(Buffer* buffer, int data) {
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = data;
newNode->next = NULL;

sem_wait(&buffer->mutex);
if (buffer->head == NULL) {
buffer->head = newNode;
buffer->tail = newNode;
} else {
buffer->tail->next = newNode;
buffer->tail = newNode;
}
sem_post(&buffer->mutex);

sem_post(&buffer->items); // Signal that an item is available


}

// Remove an item from the buffer


24
int buffer_remove(Buffer* buffer) {
sem_wait(&buffer->items); // Wait for an item to be available

if (buffer->end_of_production && buffer->head == NULL) {


// No more items and end of production has been signaled
return -1;
}

sem_wait(&buffer->mutex);
Node* removedNode = buffer->head;
int data = removedNode->data;
buffer->head = buffer->head->next;
free(removedNode);
if (buffer->head == NULL) {
buffer->tail = NULL;
}
sem_post(&buffer->mutex);

return data;
}

// Destroy the buffer and deallocate memory


void buffer_destroy(Buffer* buffer) {
while (buffer->head != NULL) {
Node* temp = buffer->head;
buffer->head = buffer->head->next;
free(temp);
}
sem_destroy(&buffer->mutex);
sem_destroy(&buffer->items);
}

// Producer thread function


void* producer(void* arg) {
Buffer* buffer = (Buffer*)arg;
for (int i = 1; i <= 10; i++) {
buffer_insert(buffer, i);
printf("Produced item: %d\n", i);
sleep(1);
}
pthread_exit(NULL);
}

// Consumer thread function


void* consumer(void* arg) {
Buffer* buffer = (Buffer*)arg;
while (true) {
int item = buffer_remove(buffer);
if (item == -1) {
// End of production signaled
printf("End of production signaled. Consumer exiting.\n");
break;
}
printf("Consumed item: %d\n", item);
sleep(2);
}
pthread_exit(NULL);
}

25
Output:

26
Experiment-7a
Aim: Write a program to implement readers-writers problem using semaphores.

Algorithm:
1. Define semaphores:
a. ‘mutex’: Controls access to the ‘readerCount’ variable, which keeps track of the number of
readers accessing the resource.
b. ‘resourceAccess’: Controls access to the shared resource. It is used by writers to acquire
exclusive access to the resource.
2. Implement reader and writer thread functions (‘reader()’ and ‘writer()’ respectively).
3. In the ‘reader()’ function:
a. Entry Section:
i. Acquire ‘mutex’ semaphore to access ‘readerCount’.
ii. Increment ‘readerCount’.
iii. If it's the first reader, block ‘resourceAccess’ semaphore to prevent writers from
accessing the resource.
b. Critical Section:
i. Read from the shared resource.
c. Exit Section:
i. Decrement ‘readerCount’.
ii. If it's the last reader, release ‘resourceAccess’ semaphore to allow writers to access
the resource.
4. In the ‘writer()’ function:
a. Entry Section:
i. Acquire ‘resourceAccess’ semaphore to gain exclusive access to the resource.
b. Critical Section:
i. Write to the shared resource.
c. Exit Section

Code:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>

#define NUM_READERS 3
#define NUM_WRITERS 2
#define MAX_READ_COUNT 3

sem_t mutex, rw_mutex;


int read_count = 0;

// Writer thread function


void* writer_thread(void* arg) {
int writer_id = *((int*)arg);
printf("Writer %d is trying to write.\n", writer_id);

sem_wait(&rw_mutex);
printf("Writer %d is writing.\n", writer_id);
printf("Writer %d finished writing.\n", writer_id);
sem_post(&rw_mutex);

27
pthread_exit(NULL);
}

// Reader thread function


void* reader_thread(void* arg) {
int reader_id = *((int*)arg);
printf("Reader %d is trying to read.\n", reader_id);

sem_wait(&mutex);
read_count++;
if (read_count == 1) {
sem_wait(&rw_mutex);
}
sem_post(&mutex);

printf("Reader %d is reading.\n", reader_id);


printf("Reader %d finished reading.\n", reader_id);

sem_wait(&mutex);
read_count--;
if (read_count == 0) {
sem_post(&rw_mutex);
}
sem_post(&mutex);

pthread_exit(NULL);
}

int main() {
pthread_t readers[NUM_READERS];
pthread_t writers[NUM_WRITERS];

sem_init(&mutex, 0, 1);
sem_init(&rw_mutex, 0, 1);

// Create writer threads


int writer_ids[NUM_WRITERS];
for (int i = 0; i < NUM_WRITERS; i++) {
writer_ids[i] = i + 1;
pthread_create(&writers[i], NULL, writer_thread, (void*)&writer_ids[i]);
}

// Create reader threads


int reader_ids[NUM_READERS];
for (int i = 0; i < NUM_READERS; i++) {
reader_ids[i] = i + 1;
pthread_create(&readers[i], NULL, reader_thread, (void*)&reader_ids[i]);
}

// Join writer threads


for (int i = 0; i < NUM_WRITERS; i++) {
pthread_join(writers[i], NULL);
}

// Join reader threads


for (int i = 0; i < NUM_READERS; i++) {
pthread_join(readers[i], NULL);
}

sem_destroy(&mutex);
28
sem_destroy(&rw_mutex);

return 0;
}

Output:

29
Experiment-7b
Aim: Write a program to implement dining philosophers problem using semaphores.

Algorithm:
1. Define a struct representing each fork and initialize a semaphore for each fork.
2. Initialize a mutex semaphore to protect critical sections where philosophers pick up and release
forks.
3. Define a function `philosopher_thread()` that simulates the behavior of a philosopher:
a. Think for a random period of time.
b. Become hungry and attempt to acquire both forks.
c. Eat for a random period of time if both forks are acquired.
d. Release both forks.
4. In the `main()` function:
a. Create threads for each philosopher, passing their IDs.
b. Join philosopher threads after they have finished execution.
5. Ensure proper initialization and destruction of semaphores.

Code:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#define NUM_PHILOSOPHERS 5 // Number of philosophers
#define MAX_MEALS 10 // Maximum number of meals
pthread_mutex_t chopsticks[NUM_PHILOSOPHERS]; // Mutex array for chopsticks
pthread_mutex_t mutex; // Mutex for critical sections
int num_meals = 0; // Counter for the number of meals
// Function prototypes
void* philosopher_thread(void* arg);
int main() {
pthread_t philosophers[NUM_PHILOSOPHERS];
// Initialize mutexes
for (int i = 0; i < NUM_PHILOSOPHERS; i++) {
pthread_mutex_init(&chopsticks[i], NULL);
}
pthread_mutex_init(&mutex, NULL);
// Create philosopher threads
for (int i = 0; i < NUM_PHILOSOPHERS; i++) {
pthread_create(&philosophers[i], NULL, philosopher_thread, (void*)&i);
}
// Join philosopher threads
for (int i = 0; i < NUM_PHILOSOPHERS; i++) {
pthread_join(philosophers[i], NULL);
}
// Destroy mutexes
for (int i = 0; i < NUM_PHILOSOPHERS; i++) {
pthread_mutex_destroy(&chopsticks[i]);
}
pthread_mutex_destroy(&mutex);
return 0;
}
// Philosopher thread function
void* philosopher_thread(void* arg) {
int philosopher_id = *(int*)arg;
30
while (1) {
pthread_mutex_lock(&mutex);
if (num_meals >= MAX_MEALS) {
printf("Philosopher %d has finished dining.\n", philosopher_id);
pthread_mutex_unlock(&mutex);
break; // Exit if philosopher has finished dining
}
pthread_mutex_unlock(&mutex);
// Try to acquire left chopstick
pthread_mutex_lock(&chopsticks[philosopher_id]);
// Try to acquire right chopstick
pthread_mutex_lock(&chopsticks[(philosopher_id + 1) % NUM_PHILOSOPHERS]);
printf("Philosopher %d is eating.\n", philosopher_id);
usleep(100000); // Simulate eating time
pthread_mutex_unlock(&chopsticks[philosopher_id]); // Release left chopstick
pthread_mutex_unlock(&chopsticks[(philosopher_id + 1) % NUM_PHILOSOPHERS]); //
Release right chopstick
pthread_mutex_lock(&mutex);
num_meals++;
pthread_mutex_unlock(&mutex);
printf("Philosopher %d is thinking.\n", philosopher_id);
usleep(100000); // Simulate thinking time
}
pthread_exit(NULL);
}

Output:

31
Experiment-8
Aim: Write a program to implement banker’s algorithm.

Algorithm:
1. Initialize available, maximum, allocation, and need matrices.
2. Define a function ‘calculateNeed()’ to calculate the need matrix, which represents the resources
that each process still needs to complete its execution.
3. Define a function ‘isSafeState()’ to check if the system is in a safe state by simulating resource
allocation and checking if the system can safely grant resources to processes without encountering
a deadlock.
4. Define a function ‘bankersAlgorithm()’ to simulate the Banker's Algorithm:
a. Calculate the need matrix.
b. Initialize a process sequence array with the sequence of processes to execute.
c. Check if the system is in a safe state using the ‘isSafeState()’ function.
d. If the system is in a safe state, print the safe sequence of processes to execute.
e. If the system is in an unsafe state (deadlock detected), print a message indicating the
deadlock.
5. In the ‘main()’ function, call the ‘bankersAlgorithm()’ function to run the Banker's Algorithm.

Code:
#include <stdio.h>
#include <stdbool.h>

// Maximum number of processes and resources


#define MAX_PROCESSES 5
#define MAX_RESOURCES 3

// Available resources
int available[MAX_RESOURCES] = {10, 5, 7};

// Maximum resources that can be allocated to each process


int maximum[MAX_PROCESSES][MAX_RESOURCES] = {
{7, 5, 3},
{3, 2, 2},
{9, 0, 2},
{2, 2, 2},
{4, 3, 3}
};

// Currently allocated resources to each process


int allocation[MAX_PROCESSES][MAX_RESOURCES] = {
{0, 1, 0},
{2, 0, 0},
{3, 0, 2},
{2, 1, 1},
{0, 0, 2}
};

// Need resources for each process


int need[MAX_PROCESSES][MAX_RESOURCES];

// Function to initialize the need matrix


void calculateNeed() {
for (int i = 0; i < MAX_PROCESSES; i++) {

32
for (int j = 0; j < MAX_RESOURCES; j++) {
need[i][j] = maximum[i][j] - allocation[i][j];
}
}
}

// Function to check if the system is in a safe state


bool isSafeState(int processSequence[]) {
int work[MAX_RESOURCES];
bool finish[MAX_PROCESSES] = {false};

// Initialize work vector with available resources


for (int i = 0; i < MAX_RESOURCES; i++) {
work[i] = available[i];
}

// Iterate over each process and allocate resources if possible


for (int i = 0; i < MAX_PROCESSES; i++) {
int process = processSequence[i];
bool canAllocate = true;

// Check if the process can be allocated resources


for (int j = 0; j < MAX_RESOURCES; j++) {
if (need[process][j] > work[j]) {
canAllocate = false;
break;
}
}

// Allocate resources to the process if possible


if (canAllocate) {
for (int j = 0; j < MAX_RESOURCES; j++) {
work[j] += allocation[process][j];
}
finish[process] = true;
}
}

// Check if all processes were able to finish


for (int i = 0; i < MAX_PROCESSES; i++) {
if (!finish[i]) {
return false; // Deadlock detected
}
}

return true; // System is in a safe state


}

// Function to simulate the Banker's Algorithm


void bankersAlgorithm() {
calculateNeed(); // Calculate need matrix

int processSequence[MAX_PROCESSES]; // Stores the sequence of processes to execute

// Initialize process sequence


for (int i = 0; i < MAX_PROCESSES; i++) {
processSequence[i] = i;
}

// Check if the system is in a safe state


33
if (isSafeState(processSequence)) {
printf("System is in a safe state\n");

// Print the sequence of processes to execute


printf("Safe sequence: ");
for (int i = 0; i < MAX_PROCESSES; i++) {
printf("%d ", processSequence[i]);
}
printf("\n");
} else {
printf("System is in an unsafe state (deadlock detected)\n");
}
}

int main() {
bankersAlgorithm(); // Run the Banker's Algorithm
return 0;
}

Output:

34
Experiment-9a
Aim: Write a program to implement LRU page replacement algorithm.

Algorithm:
1. Initialize an array ‘frames’ to represent the frames in memory, initially set to -1 to indicate empty
frames.
2. Iterate through each page in the page reference string.
3. For each page:
a. Check if the page is already present in one of the frames. If it is, continue to the next page.
b. If the page is not present in any frame, find the least recently used (LRU) page in the frames
using the ‘findLRU()’ function.
c. Replace the LRU page with the current page in the frames.
d. Increment the page fault counter.
e. Print the current state of frames along with the page fault indication.
4. After processing all pages, print the total number of page faults.
5. The ‘findLRU()’ function finds the index of the least recently used page in the frames by iterating
through the pages seen so far and finding the page that has been used the longest time ago.

Code:
#include <stdio.h>
#include <stdbool.h>

#define NUM_FRAMES 3 // Number of frames in the memory

// Function to find the least recently used page in the frames


int findLRU(int pages[], int frames[], int n) {
int index = -1, lru = 999999;
for (int i = 0; i < n; i++) {
int j;
for (j = 0; j < NUM_FRAMES; j++) {
if (frames[j] == pages[i]) {
if (j < lru) {
lru = j;
index = i;
}
break;
}
}
// If the page is not found in frames
if (j == NUM_FRAMES) return i;
}
return index;
}

// Function to implement LRU page replacement algorithm


void lruPageReplacement(int pages[], int n) {
int frames[NUM_FRAMES];
bool isPageFault = true;
int pageFaults = 0;

// Initialize frames to -1 indicating empty frame


for (int i = 0; i < NUM_FRAMES; i++) {
frames[i] = -1;
}

35
// Traverse through each page
for (int i = 0; i < n; i++) {
// Check if the page is already in a frame
bool pageFound = false;
for (int j = 0; j < NUM_FRAMES; j++) {
if (frames[j] == pages[i]) {
pageFound = true;
break;
}
}

// If page not found in frames, find the LRU page and replace it
if (!pageFound) {
int index = findLRU(pages, frames, i);
frames[index] = pages[i];
pageFaults++;
isPageFault = true;
}

// Print the current state of frames


printf("Step %d: ", i + 1);
for (int j = 0; j < NUM_FRAMES; j++) {
if (frames[j] != -1) {
printf("%d ", frames[j]);
} else {
printf("- ");
}
}
if (isPageFault) {
printf("(Page Fault)");
isPageFault = false;
}
printf("\n");
}

// Print total number of page faults


printf("\nTotal Page Faults: %d\n", pageFaults);
}

int main() {
// Page reference string
int pages[] = {7, 0, 1, 2, 0, 3, 0, 4, 2, 3, 0, 3, 2};

// Number of pages
int n = sizeof(pages) / sizeof(pages[0]);

// Perform LRU page replacement


lruPageReplacement(pages, n);

return 0;
}

36
Output:

37
Experiment-9b
Aim: Write a program to implement LRU-approximation page replacement algorithm.

Algorithm:
1. Define a ‘Page’ structure to represent a page, which includes a page ID and a boolean flag
(‘referenced’) to indicate whether the page has been referenced.
2. Implement a function ‘initializePage()’ to initialize a page with a given page ID and set the
referenced flag to false.
3. Implement a function ‘findVictim()’ to find the victim page using LRU-Approximation. It selects the
page with the least recently referenced bit as the victim.
4. Implement a function ‘lruApproximationPageReplacement()’ to perform LRU-Approximation page
replacement:
a. Initialize an array of pages (‘frames’) to represent the frames in memory, initially set to
empty pages.
b. Iterate through each page reference in the page reference string.
c. For each page reference:
i. Check if the page is already present in one of the frames. If it is, set the referenced
bit for that page and continue to the next page reference.
ii. If the page is not present in any frame, find a victim page using the ‘findVictim()’
function and replace it with the current page.
iii. Print the current state of frames along with the page fault indication.
d. After processing all page references, print the total number of page faults.
5. In the ‘main()’ function, define a page reference string and call the
‘lruApproximationPageReplacement()’ function to perform LRU-Approximation page replacement.

Code:
#include <stdio.h>
#include <stdbool.h>

#define NUM_FRAMES 3 // Number of frames in the memory

// Structure to represent a page


typedef struct {
int pageID;
bool referenced; // Usage bit
} Page;

// Function to initialize a page


Page initializePage(int pageID) {
Page newPage;
newPage.pageID = pageID;
newPage.referenced = false; // Initially not referenced
return newPage;
}

// Function to find the victim page using LRU-Approximation


int findVictim(Page frames[], int n) {
int minIndex = 0;
for (int i = 1; i < n; i++) {
// Select the page with the least recently referenced bit
if (frames[i].referenced < frames[minIndex].referenced) {
minIndex = i;
}
38
}
return minIndex;
}

// Function to perform LRU-Approximation page replacement


void lruApproximationPageReplacement(int pageReferences[], int n) {
Page frames[NUM_FRAMES];
bool isPageFault = true;
int pageFaults = 0;

// Initialize frames with empty pages


for (int i = 0; i < NUM_FRAMES; i++) {
frames[i] = initializePage(-1);
}

// Iterate through each page reference


for (int i = 0; i < n; i++) {
int currentPage = pageReferences[i];
bool pageFound = false;

// Check if the page is already in a frame


for (int j = 0; j < NUM_FRAMES; j++) {
if (frames[j].pageID == currentPage) {
frames[j].referenced = true; // Set referenced bit
pageFound = true;
break;
}
}

// If page not found in frames, replace a victim page


if (!pageFound) {
int victimIndex = findVictim(frames, NUM_FRAMES);
frames[victimIndex] = initializePage(currentPage);
pageFaults++;
isPageFault = true;
}

// Print the current state of frames along with the page fault indication
printf("Step %d: ", i + 1);
for (int j = 0; j < NUM_FRAMES; j++) {
if (frames[j].pageID != -1) {
printf("%d(%d) ", frames[j].pageID, frames[j].referenced);
} else {
printf("- ");
}
}
if (isPageFault) {
printf("(Page Fault)");
isPageFault = false;
}
printf("\n");
}

// Print total number of page faults


printf("\nTotal Page Faults: %d\n", pageFaults);
}

int main() {
// Page reference string
int pageReferences[] = {7, 0, 1, 2, 0, 3, 0, 4, 2, 3, 0, 3, 2};
39
// Number of page references
int n = sizeof(pageReferences) / sizeof(pageReferences[0]);

// Perform LRU-Approximation page replacement


lruApproximationPageReplacement(pageReferences, n);

return 0;
}

Output:

40
Experiment-9c
Aim: Write a program to implement FIFO page replacement algorithm.

Algorithm:
1. Define a function ‘findOldest()’ to find the index of the oldest page in memory by iterating through
the frames and finding the index of the page with the lowest value.
2. Implement a function ‘fifoPageReplacement()’ to perform FIFO page replacement:
a. Initialize an array of frames (‘frames’) to represent the frames in memory, initially set to -1
to indicate empty frames.
b. Initialize variables to track page faults and the index of the oldest page.
c. Iterate through each page reference in the page reference string.
d. For each page reference:
i. Check if the page is already present in one of the frames. If it is, continue to the next
page reference.
ii. If the page is not present in any frame, replace the oldest page in memory with the
current page and update the oldest index.
iii. Print the current state of frames along with the page fault indication.
e. After processing all page references, print the total number of page faults.
3. In the ‘main()’ function, define a page reference string and call the ‘fifoPageReplacement()’ function
to perform FIFO page replacement.

Code:
#include <stdio.h>
#include <stdbool.h>
#define NUM_FRAMES 3 // Number of frames in the memory
// Function to find the index of the oldest page in memory
int findOldest(int frames[], int n) {
int oldestIndex = 0;
for (int i = 1; i < n; i++) {
if (frames[i] < frames[oldestIndex]) {
oldestIndex = i;
}
}
return oldestIndex;

// Function to perform FIFO page replacement


void fifoPageReplacement(int pageReferences[], int n) {
int frames[NUM_FRAMES];
bool isPageFault = true;
int pageFaults = 0;
int oldestIndex = 0;
// Initialize frames with -1 indicating empty frame
for (int i = 0; i < NUM_FRAMES; i++) {
frames[i] = -1;
}
// Iterate through each page reference
for (int i = 0; i < n; i++) {
int currentPage = pageReferences[i];
bool pageFound = false;
// Check if the page is already in a frame
for (int j = 0; j < NUM_FRAMES; j++) {
if (frames[j] == currentPage) {
pageFound = true;
break;
41
}
}
// If page not found in frames, replace the oldest page
if (!pageFound) {
frames[oldestIndex] = currentPage;
pageFaults++;
isPageFault = true;
oldestIndex = (oldestIndex + 1) % NUM_FRAMES; // Update oldest index
}
// Print the current state of frames along with the page fault indication
printf("Step %d: ", i + 1);
for (int j = 0; j < NUM_FRAMES; j++) {
if (frames[j] != -1) {
printf("%d ", frames[j]);
} else {
printf("- ");
}
}
if (isPageFault) {
printf("(Page Fault)");
isPageFault = false;
}
printf("\n");
}
// Print total number of page faults
printf("\nTotal Page Faults: %d\n", pageFaults);
}

int main() {
// Page reference string
int pageReferences[] = {7, 0, 1, 2, 0, 3, 0, 4, 2, 3, 0, 3, 2};
// Number of page references
int n = sizeof(pageReferences) / sizeof(pageReferences[0]);
// Perform FIFO page replacement
fifoPageReplacement(pageReferences, n);

return 0;
}

Output:

42
Experiment-9d
Aim: Write a program to implement optimal page replacement algorithm.

Algorithm:
1. Define a function ‘findOptimal()’ to find the page that will not be used for the longest period of time
in the future by iterating through the remaining page references and finding the farthest reference
for each page in the frames.
2. Implement a function ‘optimalPageReplacement()’ to perform Optimal page replacement:
a. Initialize an array of frames (‘frames’) to represent the frames in memory, initially set to -1
to indicate empty frames.
b. Initialize variables to track page faults.
c. Iterate through each page reference in the page reference string.
d. For each page reference:
i. Check if the page is already present in one of the frames. If it is, continue to the next
page reference.
ii. If the page is not present in any frame, replace the page with the optimal choice
based on future references.
iii. Print the current state of frames along with the page fault indication.
e. After processing all page references, print the total number of page faults.
3. In the ‘main()’ function, define a page reference string and call the ‘optimalPageReplacement()’
function to perform Optimal page replacement.

Code:
#include <stdio.h>
#include <stdbool.h>
#include <limits.h>

#define NUM_FRAMES 3 // Number of frames in the memory

// Function to find the page that will not be used for the longest period of time in the
future
int findOptimal(int pageReferences[], int frames[], int n, int currentIndex) {
int farthestIndex = -1;
int farthestDistance = INT_MIN;

for (int i = 0; i < NUM_FRAMES; i++) {


int j;
for (j = currentIndex; j < n; j++) {
if (frames[i] == pageReferences[j]) {
if (j > farthestDistance) {
farthestDistance = j;
farthestIndex = i;
}
break;
}
}
if (j == n) return i;
}
return (farthestIndex == -1) ? 0 : farthestIndex;
}

// Function to perform Optimal page replacement


void optimalPageReplacement(int pageReferences[], int n) {
int frames[NUM_FRAMES];
43
bool isPageFault = true;
int pageFaults = 0;

// Initialize frames with -1 indicating empty frame


for (int i = 0; i < NUM_FRAMES; i++) {
frames[i] = -1;
}

// Iterate through each page reference


for (int i = 0; i < n; i++) {
int currentPage = pageReferences[i];
bool pageFound = false;

// Check if the page is already in a frame


for (int j = 0; j < NUM_FRAMES; j++) {
if (frames[j] == currentPage) {
pageFound = true;
break;
}
}

// If page not found in frames, replace the page with the optimal choice
if (!pageFound) {
int victimIndex = findOptimal(pageReferences, frames, n, i + 1);
frames[victimIndex] = currentPage;
pageFaults++;
isPageFault = true;
}

// Print the current state of frames along with the page fault indication
printf("Step %d: ", i + 1);
for (int j = 0; j < NUM_FRAMES; j++) {
if (frames[j] != -1) {
printf("%d ", frames[j]);
} else {
printf("- ");
}
}
if (isPageFault) {
printf("(Page Fault)");
isPageFault = false;
}
printf("\n");
}

// Print total number of page faults


printf("\nTotal Page Faults: %d\n", pageFaults);
}

int main() {
// Page reference string
int pageReferences[] = {7, 0, 1, 2, 0, 3, 0, 4, 2, 3, 0, 3, 2};
// Number of page references
int n = sizeof(pageReferences) / sizeof(pageReferences[0]);
// Perform Optimal page replacement
optimalPageReplacement(pageReferences, n);
return 0;
}

44
Output:

45

You might also like