1.3.
1 SIMULATE UNIX COMMAND CP
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#define BUFFER_SIZE 1024
int main(int argc, char **argv) {
int source_fd, dest_fd; // File descriptors
ssize_t count; // Number of bytes read/written
char buffer[BUFFER_SIZE]; // Buffer to hold data during copy
// Check for insufficient parameters (need source and destination file names)
if (argc < 3) {
printf("Usage: %s <source_file> <destination_file>\n", argv[0]);
return 1;
}
// Open the source file in read-only mode
source_fd = open(argv[1], O_RDONLY);
if (source_fd == -1) {
perror("Error opening source file");
return 1;
}
// Create the destination file for writing; if it exists, overwrite it
// Permissions set to read/write for the user (S_IRUSR | S_IWUSR)
dest_fd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if (dest_fd == -1) {
perror("Error creating destination file");
close(source_fd); // Close the source file before exiting
return 1;
}
// Read from source file and write to destination file in chunks
while ((count = read(source_fd, buffer, sizeof(buffer))) > 0) {
if (write(dest_fd, buffer, count) != count) {
perror("Error writing to destination file");
close(source_fd);
close(dest_fd);
return 1;
}
}
if (count == -1) {
perror("Error reading from source file");
}
// Close both files
close(source_fd);
close(dest_fd);
printf("File copied successfully from %s to %s\n", argv[1], argv[2]);
return 0;
}
OUTPUT:
*********************************************************************
2. Simulate the following CPU scheduling algorithms
(a)FCFS :
import [Link];
public class FCFSScheduler {
// Process class to hold process details
static class Process {
int id; // Process ID
int arrivalTime; // Arrival time
int burstTime; // Burst time
int completionTime; // Completion time
int waitingTime; // Waiting time
int turnaroundTime; // Turnaround time
public Process(int id, int arrivalTime, int burstTime) {
[Link] = id;
[Link] = arrivalTime;
[Link] = burstTime;
}
public static void main(String[] args) {
Scanner scanner = new Scanner([Link]);
[Link]("Enter the number of processes: ");
int n = [Link]();
Process[] processes = new Process[n];
// Input process details
for (int i = 0; i < n; i++) {
[Link]("\nEnter details for Process " + (i + 1) + ":");
[Link]("Arrival Time: ");
int arrival = [Link]();
[Link]("Burst Time: ");
int burst = [Link]();
processes[i] = new Process(i + 1, arrival, burst);
// Sort processes by arrival time for FCFS
// This is crucial for FCFS, as the process that arrives first is served first.
// If arrival times are the same, the order of input processes is maintained.
[Link](processes, (p1, p2) -> [Link] - [Link]);
// FCFS Scheduling Logic
int currentTime = 0;
float totalWaitingTime = 0;
float totalTurnaroundTime = 0;
for (Process p : processes) {
// If the CPU is idle until the process arrives
if (currentTime < [Link]) {
currentTime = [Link];
// Calculate completion time
[Link] = currentTime + [Link];
// Calculate turnaround time
[Link] = [Link] - [Link];
// Calculate waiting time
[Link] = [Link] - [Link];
// Update current time
currentTime = [Link];
totalWaitingTime += [Link];
totalTurnaroundTime += [Link];
// Display Results
[Link]("\n--- FCFS Scheduling Results ---");
[Link]("%-10s%-15s%-15s%-15s%-15s%-15s\n",
"Process", "Arrival Time", "Burst Time", "Completion Time", "Turnaround
Time", "Waiting Time");
for (Process p : processes) {
[Link]("%-10d%-15d%-15d%-15d%-15d%-15d\n",
[Link], [Link], [Link], [Link], [Link],
[Link]);
[Link]("\nAverage Waiting Time: %.2f\n", totalWaitingTime / n);
[Link]("Average Turnaround Time: %.2f\n", totalTurnaroundTime /
n);
[Link]();
OUTPUT:
Enter the number of processes: 2
Enter details for Process 1:
Arrival Time: 1
Burst Time: 9
Enter details for Process 2:
Arrival Time: 2
Burst Time: 5
--- FCFS Scheduling Results ---
Process ArrivalTime BurstTime CompletioTime TurnaroundTime Waiting Time
1 1 9 10 9 0
2 2 5 15 13 8
Average Waiting Time: 4.00
Average Turnaround Time: 11.00
[Link] the following CPU scheduling algorithms
b) SJF:
#include<stdio.h>
void main()
int bt[20],p[20],wt[20],tat[20],i,j,n,total=0,pos,temp;
float avg_wt,avg_tat;
printf("Enter number of process:");
scanf("%d",&n);
printf("\nEnter Burst Time:\n");
for(i=0;i<n;i++)
printf("p%d:",i+1);
scanf("%d",&bt[i]);
p[i]=i+1;
for(i=0;i<n;i++)
pos=i;
for(j=i+1;j<n;j++)
if(bt[j]<bt[pos])
pos=j;
}
temp=bt[i];
bt[i]=bt[pos];
bt[pos]=temp;
temp=p[i];
p[i]=p[pos];
p[pos]=temp;
wt[0]=0;
for(i=1;i<n;i++)
wt[i]=0;
for(j=0;j<i;j++)wt[i]+=bt[j];
total+=wt[i];
avg_wt=(float)total/n;
total=0;
printf("\nProcess\t Burst Time \tWaiting Time\tTurnaround Time");
for(i=0;i<n;i++)
tat[i]=bt[i]+wt[i];
total+=tat[i];
printf("\np%d\t\t %d\t\t %d\t\t\t%d",p[i],bt[i],wt[i],tat[i]);
avg_tat=(float)total/n;
printf("\n\nAverage Waiting Time=%f",avg_wt);
printf("\nAverage Turnaround Time=%f\n",avg_tat);
}
OUTPUT:
Enter number of process:2
Enter Burst Time:
p1:5
p2:4
Process Burst Time Waiting Time Turnaround Time
p2 4 0 4
p1 5 4 9
Average Waiting Time=2.000000
Average Turnaround Time=6.500000
2.( c ) Priority
import [Link];
public class priority{
public static void main(String args[]) {
Scanner s = new Scanner([Link]);
int x,n,p[],pp[],bt[],w[],t[],awt,atat,i;
p = new int[10];
pp = new int[10];
bt = new int[10];
w = new int[10];
t = new int[10];
//n is number of process
//p is process
//pp is process priority
//bt is process burst time
//w is wait time
// t is turnaround time
//awt is average waiting time
//atat is average turnaround time
[Link]("Enter the number of process : ");
n = [Link]();
[Link]("\n\t Enter burst time : time priorities \n");
for(i=0;i<n;i++)
{
[Link]("\nProcess["+(i+1)+"]:");
bt[i] = [Link]();
pp[i] = [Link]();
p[i]=i+1;
}
//sorting on the basis of priority
for(i=0;i<n-1;i++)
{
for(int j=i+1;j<n;j++)
{
if(pp[i]>pp[j])
{
x=pp[i];
pp[i]=pp[j];
pp[j]=x;
x=bt[i];
bt[i]=bt[j];
bt[j]=x;
x=p[i];
p[i]=p[j];
p[j]=x;
}
}
}
w[0]=0;
awt=0;
t[0]=bt[0];
atat=t[0];
for(i=1;i<n;i++)
{
w[i]=t[i-1];
awt+=w[i];
t[i]=w[i]+bt[i];
atat+=t[i];
}
//Displaying the process
[Link]("\n\nProcess \t Burst Time \t Wait Time \t Turn Around Time
Priority \n");
for(i=0;i<n;i++)
[Link]("\n "+p[i]+"\t\t "+bt[i]+"\t\t "+w[i]+"\t\t "+t[i]+"\t\t
"+pp[i]+"\n");
awt/=n;
atat/=n;
[Link]("\n Average Wait Time : "+awt);
[Link]("\n Average Turn Around Time : "+atat);
}
}
OUTPUT:
Enter the number of process : 3
Enter burst time : time priorities
Process[1]:2
Process[2]:3
Process[3]:2
Process Burst Time Wait Time Turn Around Time Priority
3 2 0 2 0
2 3 2 5 1
1 2 5 7 3
Average Wait Time : 2
Average Turn Around Time : 4
2(d) Round Robin
import [Link];
public class RoundRobin {
public static void main(String[] args) {
Scanner s = new Scanner([Link]);
int[] burstTime, waitingTime, turnAroundTime,
remainingBurstTime;
int numProcesses, quantum, totalWaitingTime = 0,
totalTurnAroundTime = 0;
[Link]("Enter number of processes: ");
numProcesses = [Link]();
burstTime = new int[numProcesses];
waitingTime = new int[numProcesses];
turnAroundTime = new int[numProcesses];
remainingBurstTime = new int[numProcesses];
[Link]("Enter burst time for each process:");
for (int i = 0; i < numProcesses; i++) {
[Link]("P[" + (i + 1) + "]: ");
burstTime[i] = [Link]();
remainingBurstTime[i] = burstTime[i]; // Copy burst time to
remaining burst time
[Link]("Enter time quantum: ");
quantum = [Link]();
int currentTime = 0; // Current time
int completedProcesses = 0;
// Index 'i' cycles through processes, implementing the round-robin
queue logic
for (int i = 0; completedProcesses != numProcesses; i = (i + 1) %
numProcesses) {
// Check if the current process still has remaining burst time
if (remainingBurstTime[i] > 0) {
// If remaining time is more than quantum, execute for
quantum time
if (remainingBurstTime[i] > quantum) {
currentTime += quantum;
remainingBurstTime[i] -= quantum;
// If remaining time is less than or equal to quantum, execute
completely
else {
currentTime += remainingBurstTime[i];
waitingTime[i] = currentTime - burstTime[i]; // Calculate
waiting time
remainingBurstTime[i] = 0; // Mark process as completed
completedProcesses++;
// Calculate Turnaround Time and Total Times
for (int i = 0; i < numProcesses; i++) {
turnAroundTime[i] = burstTime[i] + waitingTime[i];
totalWaitingTime += waitingTime[i];
totalTurnAroundTime += turnAroundTime[i];
// Print results
[Link]("\nProcess\t\tBurst Time\tWaiting Time\
tTurnaround Time");
[Link]("-------------------------------------------------------");
for (int i = 0; i < numProcesses; i++) {
[Link]("P[" + (i + 1) + "]\t\t" + burstTime[i] + "\t\t"
+ waitingTime[i] + "\t\t" + turnAroundTime[i]);
[Link]("\nAverage Waiting Time: " + (float)
totalWaitingTime / numProcesses);
[Link]("Average Turnaround Time: " + (float)
totalTurnAroundTime / numProcesses);
[Link]();
OUTPUT:
number of processes: 3
Enter burst time for each process:
P[1]: 3
P[2]: 2
P[3]: 4
Enter time quantum: 2
Process Burst Time Waiting Time Turnaround Time
-------------------------------------------------------
P[1] 3 4 7
P[2] 2 2 4
P[3] 4 5 9
Average Waiting Time: 3.6666667
Average Turnaround Time: 6.6666665
2.2 (a) Control the number of ports opened by the operating system with
( a )Semaphore
//These lines import necessary classes from Java's networking and concurrency
libraries. ServerSocket is used to open ports, and classes
from [Link] are crucial for multi-threading and synchronization
mechanisms.
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
public class PortControlWithSemaphore {
// Define the maximum number of concurrent ports/connections your app can
use
private static final int MAX_CONCURRENT_PORTS = 5;
//A constant integer variable is defined, setting the limit for how many ports can
be open simultaneously (in this case, 5).
private static final Semaphore SEMAPHORE = new
Semaphore(MAX_CONCURRENT_PORTS);
//A static, thread-safe (due to later synchronization) list is declared to keep track
of all currently open ServerSocket objects for later cleanup.
private static final List<ServerSocket> openSockets = new ArrayList<>();
//The main method starts here. An ExecutorService is created with a thread pool
size of 10. This service will manage the threads that attempt to open ports.
public static void main(String[] args) throws InterruptedException {
ExecutorService executor = [Link](10);
//A loop runs 10 times, creating 10 separate tasks. Each task is submitted to
the ExecutorService using a lambda expression () -> openPort(port). This
effectively tries to open ports 8000 through 8009 concurrently.
// Try to initiate 10 "port opening" tasks
for (int i = 0; i < 10; i++) {
final int port = 8000 + i;
[Link](() -> openPort(port));
//[Link]() stops the executor from accepting new
tasks. [Link](...) makes the main thread pause and wait for
up to one minute for all submitted tasks (the 10 port opening attempts) to
complete before proceeding.
[Link]();
[Link](1, [Link]);
//This block handles the cleanup phase. After all threads have finished their
simulated work, the program iterates through the openSockets list and closes all
of them.
// Clean up open sockets after demonstration
[Link]("\nClosing all open sockets.");
for (ServerSocket socket : openSockets) {
try {
[Link]();
} catch (Exception e) {
[Link]();
[Link]("Finished.");
//This is the core logic method executed by each thread. The crucial line
is [Link]();. This method blocks the current thread if all 5
permits are currently in use. The thread will wait here until a permit is available.
Once a permit is successfully acquired, the code proceeds.
private static void openPort(int portNumber) {
try {
// Acquire a permit from the semaphore (waits if limit is
reached)
[Link]("Attempting to acquire permit for port "
+portNumber + "...");
[Link]();
[Link]("Permit acquired for port " + portNumber +
". Opening port...");
//This is the "critical section"—the code that must be executed only when a
permit is held.
1. A ServerSocket is instantiated, actually opening the network port.
2. synchronized (openSockets) is used to protect the shared openSockets list from
concurrent modification by multiple threads. The socket is added to the list.
// --- CRITICAL SECTION: Code that requires a limited resource (the port) ---
ServerSocket serverSocket = new ServerSocket(portNumber);
synchronized (openSockets) {
[Link](serverSocket);
[Link]("Port " + portNumber + " opened
successfully.");
// -------------------------------------------------------------------------
// Simulate the port being used for a short duration ie for 2 sec
[Link](2000);
//This finally block is essential for robust concurrency management.
[Link](); is called here to ensure that the permit
is always returned to the semaphore pool, regardless of whether the operations
within the try block succeeded or threw an exception (e.g., if the port was
already in use and new ServerSocket(portNumber) failed). This prevents
resource leaks and deadlocks.
The catch blocks handle potential errors like InterruptedException (if the
thread is asked to stop while sleeping or waiting for a permit) or IOException (if
the port cannot be opened).
} catch (InterruptedException e) {
[Link]().interrupt();
} catch ([Link] e) {
[Link]("Could not open port " + portNumber + ": "
+ [Link]());
} finally {
// Ensure the permit is always released, even if an error occurs
[Link]("Releasing permit for port " + portNumber
+ ".");
[Link]();
OUTPUT:
Attempting to acquire permit for port 8003...
Attempting to acquire permit for port 8004...
Permit acquired for port 8004. Opening port...
Attempting to acquire permit for port 8000...
Permit acquired for port 8000. Opening port...
Attempting to acquire permit for port 8002...
Permit acquired for port 8002. Opening port...
Attempting to acquire permit for port 8001...
Permit acquired for port 8003. Opening port...
Attempting to acquire permit for port 8005...
Attempting to acquire permit for port 8006...
Permit acquired for port 8001. Opening port...
Attempting to acquire permit for port 8007...
Attempting to acquire permit for port 8008...
Attempting to acquire permit for port 8009...
Port 8000 opened successfully.
Port 8003 opened successfully.
Port 8002 opened successfully.
Port 8004 opened successfully.
Port 8001 opened successfully.
Releasing permit for port 8000.
Releasing permit for port 8003.
Permit acquired for port 8005. Opening port...
Releasing permit for port 8001.
Port 8005 opened successfully.
Releasing permit for port 8002.
Permit acquired for port 8008. Opening port...
Port 8008 opened successfully.
Releasing permit for port 8004.
Permit acquired for port 8006. Opening port...
Permit acquired for port 8009. Opening port...
Port 8006 opened successfully.
Port 8009 opened successfully.
Permit acquired for port 8007. Opening port...
Port 8007 opened successfully.
Releasing permit for port 8005.
Releasing permit for port 8008.
Releasing permit for port 8006.
Releasing permit for port 8009.
Releasing permit for port 8007.
Closing all open sockets.
Finished.
2.2(b) Control the number of ports opened by the operating system with
( b)Monitors
import [Link];
import [Link];
public class PortControllerMonitor {
// Maximum number of ports allowed at a time
private static final int MAX_CONCURRENT_PORTS = 5;
// Current number of ports in use
private int currentPorts = 0;
// ================= MONITOR METHOD =================
////Only one thread can execute these methods at a time
This is automatic locking → Monitor property
// synchronized ensures mutual exclusion
public synchronized void acquirePort(int portNumber) throws
InterruptedException {
[Link]([Link]().getName() +
": Trying to acquire port " + portNumber);
// Condition check (Monitor condition variable)
while (currentPorts == MAX_CONCURRENT_PORTS) {
[Link]([Link]().getName() +
": No ports available. Waiting...");
wait(); // Thread goes to waiting state
}
// Port is available
currentPorts++;
[Link]([Link]().getName() +
": Acquired port " + portNumber +
" | Ports in use: " + currentPorts);
// ================= MONITOR METHOD =================
public synchronized void releasePort(int portNumber) {
currentPorts--;
[Link]([Link]().getName() +
": Released port " + portNumber +
" | Ports in use: " + currentPorts);
//Wakes up waiting threads when a port is released
Standard monitor signaling
notifyAll(); // Wake up waiting threads
// ================= MAIN METHOD =================
public static void main(String[] args) {
PortControllerMonitor controller = new PortControllerMonitor();
// Create more threads than available ports
ExecutorService executor = [Link](10);
for (int i = 1; i <= 10; i++) {
final int port = 8080 + i;
[Link](() -> {
try {
[Link](port);
// Simulate port usage
[Link](2000);
} catch (InterruptedException e) {
[Link]("Thread interrupted");
} finally {
[Link](port);
});
[Link]();
OUTPUT:
pool-1-thread-1: Trying to acquire port 8081
pool-1-thread-1: Acquired port 8081 | Ports in use: 1
pool-1-thread-10: Trying to acquire port 8090
pool-1-thread-10: Acquired port 8090 | Ports in use: 2
pool-1-thread-9: Trying to acquire port 8089
pool-1-thread-9: Acquired port 8089 | Ports in use: 3
pool-1-thread-8: Trying to acquire port 8088
pool-1-thread-8: Acquired port 8088 | Ports in use: 4
pool-1-thread-7: Trying to acquire port 8087
pool-1-thread-7: Acquired port 8087 | Ports in use: 5
pool-1-thread-6: Trying to acquire port 8086
pool-1-thread-6: No ports available. Waiting...
pool-1-thread-5: Trying to acquire port 8085
pool-1-thread-5: No ports available. Waiting...
pool-1-thread-4: Trying to acquire port 8084
pool-1-thread-4: No ports available. Waiting...
pool-1-thread-3: Trying to acquire port 8083
pool-1-thread-3: No ports available. Waiting...
pool-1-thread-2: Trying to acquire port 8082
pool-1-thread-2: No ports available. Waiting...
pool-1-thread-10: Released port 8090 | Ports in use: 4
pool-1-thread-6: Acquired port 8086 | Ports in use: 5
pool-1-thread-2: No ports available. Waiting...
pool-1-thread-3: No ports available. Waiting...
pool-1-thread-4: No ports available. Waiting...
pool-1-thread-5: No ports available. Waiting...
pool-1-thread-8: Released port 8088 | Ports in use: 4
pool-1-thread-7: Released port 8087 | Ports in use: 3
pool-1-thread-9: Released port 8089 | Ports in use: 2
pool-1-thread-1: Released port 8081 | Ports in use: 1
pool-1-thread-5: Acquired port 8085 | Ports in use: 2
pool-1-thread-4: Acquired port 8084 | Ports in use: 3
pool-1-thread-3: Acquired port 8083 | Ports in use: 4
pool-1-thread-2: Acquired port 8082 | Ports in use: 5
pool-1-thread-6: Released port 8086 | Ports in use: 4
pool-1-thread-5: Released port 8085 | Ports in use: 3
pool-1-thread-4: Released port 8084 | Ports in use: 2
pool-1-thread-3: Released port 8083 | Ports in use: 1
pool-1-thread-2: Released port 8082 | Ports in use: 0
---------------------------------**********-------------------------------------------
3.1 Write a program to illustrate concurrent execution of threads using
pthreads library.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> // For sleep()
#include <pthread.h>
// Function that the first thread will execute
void *thread_function1(void *arg) {
for (int i = 0; i < 5; i++) {
printf("Thread 1 is running (iteration %d)\n", i);
sleep(1); // Sleep for 1 second to illustrate concurrency
}
printf("Thread 1 finished.\n");
return NULL;
// Function that the second thread will execute
void *thread_function2(void *arg) {
for (int i = 0; i < 3; i++) {
printf("Thread 2 is running (iteration %d)\n", i);
sleep(2); // Sleep for 2 seconds
printf("Thread 2 finished.\n");
return NULL;
int main() {
pthread_t thread1_id;
pthread_t thread2_id;
printf("Main thread: Creating Thread 1 and Thread 2\n");
// Create the first thread
// pthread_create(thread_pointer, attributes, start_routine,
argument)
if (pthread_create(&thread1_id, NULL, thread_function1, NULL) !=
0) {
fprintf(stderr, "Error creating thread 1\n");
return 1;
}
// Create the second thread
if (pthread_create(&thread2_id, NULL, thread_function2, NULL) !=
0) {
fprintf(stderr, "Error creating thread 2\n");
return 1;
printf("Main thread: Both threads created. Waiting for them to
finish...\n");
// Wait for the first thread to finish
if (pthread_join(thread1_id, NULL) != 0) {
fprintf(stderr, "Error joining thread 1\n");
return 1;
// Wait for the second thread to finish
if (pthread_join(thread2_id, NULL) != 0) {
fprintf(stderr, "Error joining thread 2\n");
return 1;
printf("Main thread: Both threads finished. Exiting.\n");
return 0;
OUTPUT:
Main thread: Creating Thread 1 and Thread 2
Thread 1 is running (iteration 0)
Thread 2 is running (iteration 0)
Main thread: Both threads created. Waiting for them to finish...
Thread 1 is running (iteration 1)
Thread 2 is running (iteration 1)
Thread 1 is running (iteration 2)
Thread 1 is running (iteration 3)
Thread 2 is running (iteration 2)
Thread 1 is running (iteration 4)
Thread 1 finished.
Thread 2 finished.
Main thread: Both threads finished. Exiting.
3.2 Write a program to solve producer-consumer problem using Semaphores.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#define BUFFER_SIZE 10
#define NUM_PRODUCERS 1
#define NUM_CONSUMERS 1
int buffer[BUFFER_SIZE];
int in = 0; // Index for the next item to be produced
int out = 0; // Index for the next item to be consumed
sem_t empty; // Counts the number of empty slots in the buffer
sem_t full; // Counts the number of full slots in the buffer
pthread_mutex_t mutex; // Mutex lock for critical section (buffer
access)
void* producer(void* arg) {
int item_produced;
for (int i = 0; i < 20; i++) { // Produce 20 items
item_produced = i;
// Wait for an empty slot (decrement empty semaphore)
sem_wait(&empty);
// Acquire the mutex lock
pthread_mutex_lock(&mutex);
// --- Critical Section ---
buffer[in] = item_produced;
printf("Producer produced item %d at slot %d\n",
item_produced, in);
in = (in + 1) % BUFFER_SIZE;
// --- End of Critical Section ---
// Release the mutex lock
pthread_mutex_unlock(&mutex);
// Signal that a slot is full (increment full semaphore)
sem_post(&full);
// Sleep for a short duration to simulate work
usleep(rand() % 1000000);
return NULL;
void* consumer(void* arg) {
int item_consumed;
for (int i = 0; i < 20; i++) { // Consume 20 items
// Wait for a full slot (decrement full semaphore)
sem_wait(&full);
// Acquire the mutex lock
pthread_mutex_lock(&mutex);
// --- Critical Section ---
item_consumed = buffer[out];
printf("Consumer consumed item %d from slot %d\n",
item_consumed, out);
out = (out + 1) % BUFFER_SIZE;
// --- End of Critical Section ---
// Release the mutex lock
pthread_mutex_unlock(&mutex);
// Signal that a slot is empty (increment empty semaphore)
sem_post(&empty);
// Sleep for a short duration to simulate work
usleep(rand() % 2000000);
return NULL;
int main() {
pthread_t prod_threads[NUM_PRODUCERS],
cons_threads[NUM_CONSUMERS];
// Initialize semaphores:
// sem_init(&semaphore, pshared, value);
// pshared = 0 means the semaphore is shared between threads of a
process.
// initial value of 'empty' is BUFFER_SIZE
sem_init(&empty, 0, BUFFER_SIZE);
// initial value of 'full' is 0
sem_init(&full, 0, 0);
// Initialize mutex
pthread_mutex_init(&mutex, NULL);
// Create producer threads
for (int i = 0; i < NUM_PRODUCERS; i++) {
pthread_create(&prod_threads[i], NULL, producer, NULL);
// Create consumer threads
for (int i = 0; i < NUM_CONSUMERS; i++) {
pthread_create(&cons_threads[i], NULL, consumer, NULL);
}
// Join threads (wait for them to finish)
for (int i = 0; i < NUM_PRODUCERS; i++) {
pthread_join(prod_threads[i], NULL);
for (int i = 0; i < NUM_CONSUMERS; i++) {
pthread_join(cons_threads[i], NULL);
// Destroy semaphores and mutex
sem_destroy(&empty);
sem_destroy(&full);
pthread_mutex_destroy(&mutex);
return 0;
OUTPUT:
Producer produced item 0 at slot 0
Consumer consumed item 0 from slot 0
Producer produced item 1 at slot 1
Consumer consumed item 1 from slot 1
Producer produced item 2 at slot 2
Consumer consumed item 2 from slot 2
Producer produced item 3 at slot 3
Consumer consumed item 3 from slot 3
Producer produced item 4 at slot 4
Producer produced item 5 at slot 5
Consumer consumed item 4 from slot 4
Producer produced item 6 at slot 6
Producer produced item 7 at slot 7
Producer produced item 8 at slot 8
Consumer consumed item 5 from slot 5
Producer produced item 9 at slot 9
Consumer consumed item 6 from slot 6
Producer produced item 10 at slot 0
Producer produced item 11 at slot 1
Producer produced item 12 at slot 2
Producer produced item 13 at slot 3
Producer produced item 14 at slot 4
Consumer consumed item 7 from slot 7
Producer produced item 15 at slot 5
Consumer consumed item 8 from slot 8
Consumer consumed item 9 from slot 9
Producer produced item 16 at slot 6
Producer produced item 17 at slot 7
Consumer consumed item 10 from slot 0
Producer produced item 18 at slot 8
Consumer consumed item 11 from slot 1
Producer produced item 19 at slot 9
Consumer consumed item 12 from slot 2
Consumer consumed item 13 from slot 3
Consumer consumed item 14 from slot 4
Consumer consumed item 15 from slot 5
Consumer consumed item 16 from slot 6
Consumer consumed item 17 from slot 7
Consumer consumed item 18 from slot 8
Consumer consumed item 19 from slot 9
4.1 Implement the following memory allocation methods for fixed partition
a) First fit b) Worst fit c) Best fit
(a) FIRST FIT
public class FirstFitMemoryAllocation {
/*
* Implements the First Fit memory allocation algorithm.
* blockSize Array of fixed memory block sizes.
* m The number of memory blocks.
* processSize Array of process sizes.
* n The number of processes.
*/
public static void implementFirstFit(int[] blockSize, int m, int[] processSize,
int n) {
int[] allocation = new int[n]; // Array to store the block index allocated to a
process
for (int i = 0; i < n; i++) { // Iterate through each process
for (int j = 0; j < m; j++) { // Find the first sufficient block
if (blockSize[j] >= processSize[i]) {
allocation[i] = j; // Allocate block j to process i
blockSize[j] -= processSize[i]; // Reduce available memory in the
block
break; // Move to the next process
[Link]("\nProcess No.\tProcess Size\tBlock no.");
for (int i = 0; i < n; i++) {
[Link](" " + (i + 1) + "\t\t" + processSize[i] + "\t\t");
if (allocation[i] != -1) {
[Link](allocation[i] + 1);
} else {
[Link]("Not Allocated");
public static void main(String[] args) {
int[] blockSize = {100, 500, 200, 300, 600}; // Example memory block sizes
int[] processSize = {212, 417, 112, 426}; // Example process sizes
int m = [Link];
int n = [Link];
implementFirstFit(blockSize, m, processSize, n);
OUTPUT:
Process [Link] Size Block no.
1 212 2
2 417 5
3 112 2
4 426 1
(b) Worst fit
// Java implementation of worst - Fit algorithm
public class GFG
// Method to allocate memory to blocks as per worst fit
// algorithm
static void worstFit(int blockSize[], int m, int processSize[],
int n)
// Stores block id of the block allocated to a
// process
int allocation[] = new int[n];
// Initially no block is assigned to any process
for (int i = 0; i < [Link]; i++)
allocation[i] = -1;
// pick each process and find suitable blocks
// according to its size ad assign to it
for (int i=0; i<n; i++)
// Find the best fit block for current process
int wstIdx = -1;
for (int j=0; j<m; j++)
if (blockSize[j] >= processSize[i])
if (wstIdx == -1)
wstIdx = j;
else if (blockSize[wstIdx] < blockSize[j])
wstIdx = j;
// If we could find a block for current process
if (wstIdx != -1)
// allocate block j to p[i] process
allocation[i] = wstIdx;
// Reduce available memory in this block.
blockSize[wstIdx] -= processSize[i];
[Link]("\nProcess No.\tProcess Size\tBlock no.");
for (int i = 0; i < n; i++)
[Link](" " + (i+1) + "\t\t" + processSize[i] + "\t\t");
if (allocation[i] != -1)
[Link](allocation[i] + 1);
else
[Link]("Not Allocated");
[Link]();
}
// Driver Method
public static void main(String[] args)
int blockSize[] = {100, 500, 200, 300, 600};
int processSize[] = {212, 417, 112, 426};
int m = [Link];
int n = [Link];
worstFit(blockSize, m, processSize, n);
OUTPUT:
Process No. Process Size Block no.
1 212 5
2 417 2
3 112 5
4 426 Not Allocated
( C ) BEST FIT
import [Link];
public class BestFitFixedPartition {
/**
* Allocates processes to memory blocks using the Best Fit algorithm in a fixed
partitioning scheme.
*
* @param blockSize Array of sizes of memory blocks. This array will be
modified to reflect remaining free space.
* @param processSize Array of sizes of processes that need to be allocated
memory.
*/
public static void bestFit(int[] blockSize, int[] processSize) {
int m = [Link];
int n = [Link];
// Array to store the block ID allocated to a process
// (allocation[i] = j means process i is allocated to block j)
int[] allocation = new int[n];
// Initially, set all processes to not allocated (-1)
[Link](allocation, -1);
// Traverse all processes
for (int i = 0; i < n; i++) {
// Find the best fit block for the current process
int bestIdx = -1;
for (int j = 0; j < m; j++) {
if (blockSize[j] >= processSize[i]) {
if (bestIdx == -1 || blockSize[j] < blockSize[bestIdx]) {
bestIdx = j;
}
}
}
// If a suitable block was found
if (bestIdx != -1) {
// Allocate the block to the process
allocation[i] = bestIdx;
// Reduce available memory in that block
blockSize[bestIdx] -= processSize[i];
}
}
[Link]("\nProcess No. Process Size Block No.");
for (int i = 0; i < n; i++) {
[Link](" " + (i + 1) + " " + processSize[i] + " ");
if (allocation[i] != -1) {
[Link](allocation[i] + 1);
} else {
[Link]("Not Allocated");
}
[Link]();
}
}
// Driver Method
public static void main(String[] args) {
// Example memory blocks (fixed partitions)
int[] blockSize = {100, 500, 200, 300, 600};
// Example processes with their required sizes
int[] processSize = {212, 417, 112, 426};
[Link]("Initial Memory Blocks: " +
[Link](blockSize));
[Link]("Processes to Allocate: " +
[Link](processSize));
bestFit(blockSize, processSize);
[Link]("\nRemaining Block Sizes: " +
[Link](blockSize));
}
}
OUTPUT:
Initial Memory Blocks: [100, 500, 200, 300, 600]
Processes to Allocate: [212, 417, 112, 426]
Process No. Process Size Block No.
1 212 4
2 417 2
3 112 3
4 426 5
Remaining Block Sizes: [100, 83, 88, 88, 174]
4(b) Simulate the following page replacement algorithms
a) FIFO b) LRU c) LFU
(a)FIFO
// Java implementation of FIFO page replacement
// in Operating Systems.
import [Link];
import [Link];
import [Link];
class Test
{
// Method to find page faults using FIFO
static int pageFaults(int pages[], int n, int capacity)
{
// To represent set of current pages. We use
// an unordered_set so that we quickly check
// if a page is present in set or not
HashSet<Integer> s = new HashSet<>(capacity);
// To store the pages in FIFO manner
Queue<Integer> indexes = new LinkedList<>() ;
// Start from initial page
int page_faults = 0;
for (int i=0; i<n; i++)
{
// Check if the set can hold more pages
if ([Link]() < capacity)
{
// Insert it into set if not present
// already which represents page fault
if ()
{
[Link](pages[i]);
// increment page fault
page_faults++;
// Push the current page into the queue
[Link](pages[i]);
}
}
// If the set is full then need to perform FIFO
// i.e. remove the first page of the queue from
// set and queue both and insert the current page
else
{
// Check if current page is not already
// present in the set
if ()
{
//Pop the first page from the queue
int val = [Link]();
[Link]();
// Remove the indexes page
[Link](val);
// insert the current page
[Link](pages[i]);
// push the current page into
// the queue
[Link](pages[i]);
// Increment page faults
page_faults++;
}
}
}
return page_faults;
}
// Driver method
public static void main(String args[])
{
int pages[] = {7, 0, 1, 2, 0, 3, 0, 4,
2, 3, 0, 3, 2};
int capacity = 4;
[Link](pageFaults(pages, [Link], capacity));
}
}
OUTPUT: 7
(b) LRU
// Java implementation of above algorithm
import [Link];
import [Link];
import [Link];
class Test
{
// Method to find page faults using indexes
static int pageFaults(int pages[], int n, int capacity)
{
// To represent set of current pages. We use
// an unordered_set so that we quickly check
// if a page is present in set or not
HashSet<Integer> s = new HashSet<>(capacity);
// To store least recently used indexes
// of pages.
HashMap<Integer, Integer> indexes = new HashMap<>();
// Start from initial page
int page_faults = 0;
for (int i=0; i<n; i++)
{
// Check if the set can hold more pages
if ([Link]() < capacity)
{
// Insert it into set if not present
// already which represents page fault
if ()
{
[Link](pages[i]);
// increment page fault
page_faults++;
}
// Store the recently used index of
// each page
[Link](pages[i], i);
}
// If the set is full then need to perform lru
// i.e. remove the least recently used page
// and insert the current page
else
{
// Check if current page is not already
// present in the set
if ()
{
// Find the least recently used pages
// that is present in the set
int lru = Integer.MAX_VALUE, val=Integer.MIN_VALUE;
Iterator<Integer> itr = [Link]();
while ([Link]()) {
int temp = [Link]();
if ([Link](temp) < lru)
{
lru = [Link](temp);
val = temp;
}
}
// Remove the indexes page
[Link](val);
//remove lru from hashmap
[Link](val);
// insert the current page
[Link](pages[i]);
// Increment page faults
page_faults++;
}
// Update the current page index
[Link](pages[i], i);
}
}
return page_faults;
}
// Driver method
public static void main(String args[])
{
int pages[] = {7, 0, 1, 2, 0, 3, 0, 4, 2, 3, 0, 3, 2};
int capacity = 4;
[Link](pageFaults(pages, [Link], capacity));
}
}
OUTPUT: 6
( C ) LFU
import [Link].*;
public class LFUPageFaults {
/* Counts no. of page faults */
static int pageFaults(int n, int c, int[] pages)
{
// Initialise count to 0
int count = 0;
// To store elements in memory of size c
List<Integer> v = new ArrayList<Integer>();
// To store frequency of pages
Map<Integer, Integer> mp
= new HashMap<Integer, Integer>();
for (int i = 0; i <= n - 1; i++) {
// Find if element is present in memory or not
int idx = [Link](pages[i]);
// If element is not present
if (idx == -1) {
// If memory is full
if ([Link]() == c) {
// Decrease the frequency
int leastFreqPage = [Link](0);
[Link](leastFreqPage,
[Link](leastFreqPage) - 1);
// Remove the first element as
// It is least frequently used
[Link](0);
}
// Add the element at the end of memory
[Link](pages[i]);
// Increase its frequency
[Link](pages[i],
[Link](pages[i], 0) + 1);
// Increment the count
count++;
}
else {
// If element is present
// Remove the element
// And add it at the end
// Increase its frequency
int page = [Link](idx);
[Link](page);
[Link](page, [Link](page) + 1);
}
// Compare frequency with other pages
// starting from the 2nd last page
int k = [Link]() - 2;
// Sort the pages based on their frequency
// And time at which they arrive
// if frequency is same
// then, the page arriving first must be placed
// first
while (k >= 0
&& [Link]([Link](k))
> [Link]([Link](k + 1))) {
[Link](v, k, k + 1);
k--;
}
}
// Return total page faults
return count;
}
/* Driver program to test pageFaults function*/
public static void main(String[] args)
{
int[] pages = { 1, 2, 3, 4, 2, 1, 5 };
int n = 7, c = 3;
[Link]("Page Faults = "
+ pageFaults(n, c, pages));
[Link]("Page Hits = "
+ (n - pageFaults(n, c, pages)));
}
}
OUTPUT:
Page Faults = 6
Page Hits = 1
4(c) Simulate Paging Technique of memory management
import [Link].*;
public class PagingSimulation {
// Define constants for memory sizes
final int MEMORY_SIZE = 256; // Physical memory size in bytes
final int PAGE_SIZE = 32; // Page/Frame size in bytes
final int NUM_FRAMES = MEMORY_SIZE / PAGE_SIZE; // Number of
physical frames (8)
final int NUM_PAGES = 16; // Number of logical pages (for a conceptual
process)
// Data structures
int[] physicalMemory; // Represents physical memory frames
int[] pageTable; // Maps logical pages to physical frames
boolean[] frameStatus; // Tracks availability of physical frames
public PagingSimulation() {
physicalMemory = new int[MEMORY_SIZE];
pageTable = new int[NUM_PAGES];
frameStatus = new boolean[NUM_FRAMES];
[Link](pageTable, -1); // Initialize page table: -1 indicates not loaded
[Link](frameStatus, false); // All frames are initially free
}
// Load a page into an available frame
public void loadPage(int pageNum, int frameNum) {
if (pageNum >= 0 && pageNum < NUM_PAGES && frameNum >= 0 &&
frameNum < NUM_FRAMES) {
pageTable[pageNum] = frameNum;
frameStatus[frameNum] = true;
[Link]("Page " + pageNum + " loaded into Frame " + frameNum);
} else {
[Link]("Invalid page or frame number.");
}
}
// Translate a logical address to a physical address
public int translateAddress(int logicalAddress) {
// A logical address consists of a page number and an offset
int pageNum = logicalAddress / PAGE_SIZE; // Page number
int offset = logicalAddress % PAGE_SIZE; // Offset within the page
if (pageNum >= 0 && pageNum < NUM_PAGES) {
int frameNum = pageTable[pageNum];
if (frameNum != -1) {
// Address translation: Physical Address = (Frame Number * Page Size) +
Offset
int physicalAddress = (frameNum * PAGE_SIZE) + offset;
return physicalAddress;
} else {
[Link]("Page Fault: Page " + pageNum + " not in memory.");
// In a real OS, a page fault handler would load the page from secondary
storage
return -1; // Indicate page fault
}
} else {
[Link]("Invalid logical address.");
return -1;
}
}
// Helper method to find the first available frame (simple allocation)
public int findAvailableFrame() {
for (int i = 0; i < NUM_FRAMES; i++) {
if (!frameStatus[i]) {
return i;
}
}
return -1; // No free frames
}
public static void main(String[] args) {
PagingSimulation simulator = new PagingSimulation();
Scanner in = new Scanner([Link]);
// Simulate loading a few pages
int frame1 = [Link]();
if (frame1 != -1) [Link](0, frame1);
int frame2 = [Link]();
if (frame2 != -1) [Link](1, frame2);
int frame3 = [Link]();
if (frame3 != -1) [Link](2, frame3);
// User interaction for address translation
while (true) {
[Link]("\nEnter a Logical Address to translate (or a negative
number to exit):");
int logicalAddr = [Link]();
if (logicalAddr < 0) break;
int physicalAddr = [Link](logicalAddr);
if (physicalAddr != -1) {
[Link]("Logical Address " + logicalAddr + " translates to
Physical Address " + physicalAddr);
}
}
[Link]();
}
}
OUTPUT:
Page 0 loaded into Frame 0
Page 1 loaded into Frame 1
Page 2 loaded into Frame 2
Enter a Logical Address to translate (or a negative number to exit):
1000
Invalid logical address.
Enter a Logical Address to translate (or a negative number to exit):
1
Logical Address 1 translates to Physical Address 1
Enter a Logical Address to translate (or a negative number to exit):
3
Logical Address 3 translates to Physical Address 3
Enter a Logical Address to translate (or a negative number to exit):
0
Logical Address 0 translates to Physical Address 0
Enter a Logical Address to translate (or a negative number to exit):
-1