OS Practical File
OS Practical File
TECHNOLOGY
(EAST CAMPUS)
Geeta Colony, New Delhi-110031
OPERATING SYSTEMS
Course Code: CBCPC09
PRACTICAL FILE
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);
}
int main() {
pid_t child_pid;
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
int main() {
pthread_t threads[NUM_THREADS];
int rc;
long t;
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;
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}
};
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;
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;
}
}
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}
};
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;
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}
};
// 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;
// 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--;
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}
};
// 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);
}
if (pid < 0) {
perror("Fork failed");
exit(EXIT_FAILURE);
}
16
printf("Parent received message from child: %s\n", buffer);
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;
pthread_exit(NULL);
}
int main() {
pthread_t threads[NUM_THREADS];
int rc;
long t;
// 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);
}
}
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>
// 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);
buffer_destroy(&buffer);
return 0;
}
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_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;
}
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_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);
}
sem_wait(&mutex);
read_count++;
if (read_count == 1) {
sem_wait(&rw_mutex);
}
sem_post(&mutex);
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);
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>
// Available resources
int available[MAX_RESOURCES] = {10, 5, 7};
32
for (int j = 0; j < MAX_RESOURCES; j++) {
need[i][j] = maximum[i][j] - allocation[i][j];
}
}
}
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>
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;
}
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]);
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>
// 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");
}
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]);
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;
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>
// 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;
// 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");
}
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