OS Lab Manual (2)
OS Lab Manual (2)
LABORATORY RECORD
NAME :
REGISTER NUMBER :
YEAR/SEM :
SUB. CODE/TITLE :
Certified that this is a Bonafide record of work done by the above student during the academic year
.
Interpretation (4)
Observation (4)
Preparation (4)
Viva-Voce (4)
Results (4)
Page No.
Total
S. No Date Name of the Experiments Sign
(20)
Inter Process
4
Communication
Producer - Consumer
5
Problem
6 Banker’s Algorithm
Page Replacement
7
Algorithms
File Organization
9
Techniques
2
U21CS404 – OPEARTING SYSTEMS LAB
VISION AND MISSION OF THE INSTITUTION
Vision
Mission
❖ Commitment to offer value-based education and enhancement of practical skills.
❖ Continuous assessment of teaching and learning processes through scholarly activities.
❖ Enriching research and innovation activities in collaboration with industry and institutes of repute.
❖ Ensuring the academic processes to uphold culture, ethics and social responsibilities.
Vision
❖ To be a premier centre for education, dissemination of knowledge and research in the frontier areas
of computer science and engineering to serve the community with moral values.
Mission
❖ Provide holistic education incorporating the state-of-the-art technologies to produce successful
Professionals
❖ Facilitate the students to pursue higher education and research in the areas related to Computer
Science and Engineering.
❖ Promote strong collaborations with the industries and steer the students to nurture their interest in
continuous learning to meet the changing needs of the society.
3
EX.NO : 01 (a)
BASICS OF UNIX COMMANDS - INTRODUCTION TO UNIX
DATE :
AIM:
To explore the fundamentals and architecture of UNIX and Linux, understanding their evolution,
key components, and impact on modern computing.
UNIX:
UNIX is a pioneering multi-user operating system developed in 1969 by Ken Thompson and
Dennis Ritchie at AT&T's Bell Labs, evolving from the MULTICS project. Its design emphasizes
simplicity and flexibility, making it powerful for various computing needs. Significantly, by 1980,
UNIX was rewritten in C, enhancing its portability and allowing it to run on diverse hardware systems.
This transition to C marked a major advancement, making UNIX widely adaptable and foundational to
the development of many modern operating systems, including Linux and BSD variants.
LINUX:
Linux, an open-source operating system created by Linus Torvalds in 1991, mirrors UNIX in its
compatibility with UNIX commands, showcasing its adaptability and comprehensive functionality. Its
development underlines a commitment to openness and flexibility, with a key feature being its capability
to coexist with other operating systems, such as Windows and UNIX, from its inception. This makes
Linux a versatile and widely adopted choice for users and developers seeking a robust, interoperable
computing platform.
1. UNIX Kernel: The kernel acts as the core of the operating system, managing tasks,
scheduling processes, and executing the core functions of the OS. It efficiently allocates
resources and decides the sequencing of program execution.
2. Shells: Serving as the command interpreter, the shell processes user commands,
providing an interface between the user and the kernel. It interprets and executes the
commands entered by the user.
3. Tools and Applications: This layer includes various utilities and software applications
that perform specific tasks, enhancing the functionality and user experience of the Linux
system.
CONCLUSION:
UNIX and Linux have revolutionized computing with their simplicity, adaptability, and open-
source nature, providing essential platforms for innovation and development in the tech world.
4
EX.NO : 01 (b)
BASICS OF UNIX COMMANDS - BASIC UNIX COMMANDS
DATE :
AIM:
a) Date: The date command is used to check the current date and time in Unix systems.
Command Description
b) Cal: The cal command is used to display a calendar for a specified month and year in Unix
systems.
Command Description
c) Echo: The echo command is used to print messages or text to the screen in Unix systems.
Command Description
d) Directory and File: To create a file and a directory in Unix systems using mkdir and touch.
Command Description
e) List: The ls command is used to list files and directories in a specified directory in Unix systems.
Command Description
f) Other commands:
Command Description
6
1010 Assuming binary input (due to
previous ibase=2), interpreted and
converted to hexadecimal.
sqrt(196) Calculates the square root of 196.
for(i=1;i<3;i=i+1)I Loop structure (seems like a typo: I at
the end might be incorrect).
scale=2 Sets the precision to 2 decimal places.
s(3.14) Sine function of 3.14 with bc -l (math
library loaded).
7
OUTPUT:
RESULT:
The execution of basic UNIX commands was completed successfully.
8
EX.NO : 01 (c)
BASICS OF UNIX COMMANDS - UNIX EDITORS
DATE :
AIM:
To study various UNIX text editors such as vi, ed, ex, and EMACS.
An editor in UNIX is a program that enables a user to view portions of a file on the screen and
modify its content by typing. UNIX supports a variety of editors, including ed, ex, vi, and EMACS.
a) Vi Editor Commands
Motion Commands
Key/Command Action
9
Deletion Commands
Key/Command Action
Key/Command Action
DEPARTMENT OF IT
Preparation (Algorithm) 4
Observation (Program) 4
Results (Output) 4
Interpretation (Validation) 4
Viva-Voce 4
Total 20
RESULT:
The study and exploration of UNIX editors, including vi, ed, ex, and EMACS, were completed
successfully.
10
EX.NO : 02 (a)
PROGRAMS ON SYSTEM CALLS
DATE :
AIM:
To write a C program that demonstrates the use of fundamental UNIX operating system calls for
process management: fork(), wait(), and getpid().
ALGORITHM:
STEP 1: Start the program by including necessary header files.
STEP 2: Declare a variable of type pid_t to store the process ID.
STEP 3: Use the fork() system call to create a new process.
STEP 4: Check the return value of fork().
STEP 5: In the parent process, use the waitpid() system call with the child's PID to wait for the
child process to complete.
STEP 6: After waiting for the child process to complete, print a message in the parent process
indicating the completion of the child process.
STEP 7: End the program by returning EXIT_SUCCESS to indicate successful execution.
PROGRAM:
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
int main()
{
pid_t pid;
int status;
// Create a new process
pid = fork();
if (pid == -1)
{
// if fork() returns -1, an error occurred
perror("fork failed");
exit(EXIT_FAILURE);
}
else if (pid == 0)
{
// Child process
printf("Child Process: PID = %d\n", getpid());
printf("Child Process: Parent PID = %d\n", getppid());
// Execute an action here. For example, sleep for 2 seconds
sleep(2);
printf("Child Process: Exiting...\n");
exit(EXIT_SUCCESS);
}
11
else
{
// Parent process
printf("Parent Process: PID = %d\n", getpid());
printf("Parent Process: Child PID = %d\n", pid);
// Wait for the child to complete
waitpid(pid, &status, 0);
printf("Parent Process: Child %d finished execution\n", pid);
}
return EXIT_SUCCESS;
}
OUTPUT:
RESULT:
The C program has been successfully executed for managing processes with system calls.
12
EX.NO : 02 (b)
PROGRAMS ON SYSTEM CALLS
DATE :
AIM:
To write a C program that demonstrates the use of fundamental UNIX operating system calls for
file manipulation: open(), read(), and close().
ALGORITHM:
STEP 1: Start the program by including necessary header files.
STEP 2: Declare a variable of type pid_t to store the process ID.
STEP 3: Use the open() system call to open an existing file for reading.
STEP 4: Use the read() system call to read data from the file.
STEP 5: Use the close() system call to close the file, passing the file descriptor as an argument.
PROGRAM:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
int fileDescriptor;
ssize_t bytesRead;
char buffer[100];
// Open a file for reading
fileDescriptor = open("example.txt", O_RDONLY);
if (fileDescriptor < 0)
{
perror("Failed to open the file");
return EXIT_FAILURE;
}
// Read up to 100 bytes from the file
bytesRead = read(fileDescriptor, buffer, sizeof(buffer) - 1);
if (bytesRead < 0)
{
perror("Failed to read the file");
close(fileDescriptor);
return EXIT_FAILURE;
}
// Null-terminate the string we've read and print it
buffer[bytesRead] = '\0';
printf("Content read from the file:\n%s\n", buffer);
// Close the file descriptor
if (close(fileDescriptor) < 0)
{
perror("Failed to close the file");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
13
OUTPUT:
DEPARTMENT OF IT
Preparation (Algorithm) 4
Observation (Program) 4
Results (Output) 4
Interpretation (Validation) 4
Viva-Voce 4
Total 20
RESULT:
The C program has been successfully executed with system calls file manipulation.
14
EX.NO : 03 (a)
CPU SCHEDULING ALGORITHMS - FCFS
DATE :
AIM:
To calculate and display the waiting time and turn-around time for a set of processes scheduled
using the First Come, First Served (FCFS) algorithm, and to compute the average waiting time and
average turn-around time for all the processes.
ALGORITHM:
STEP 1: Start the program.
STEP 2: Define a structure to store process ID and burst time for each process.
STEP 3: Calculate waiting times by accumulating previous processes' burst times.
STEP 4: Calculate turn-around times by adding each process's burst time to its waiting time.
STEP 5: Compute and display the average waiting time and turn-around time for all processes.
STEP 6: Display process details including PID, burst time, waiting time, and turn-around time.
PROGRAM:
#include <stdio.h>
// Define a structure for processes
struct process
{
int pid; // Process ID
int bt; // Burst Time
};
void findWaitingTime(struct process proc[], int n, int wt[])
{
wt[0] = 0; // first process has no waiting time
for (int i = 1; i < n; i++)
{
wt[i] = proc[i-1].bt + wt[i-1];
}
}
void findTurnAroundTime(struct process proc[], int n, int wt[], int tat[])
{
for (int i = 0; i < n; i++)
{
tat[i] = proc[i].bt + wt[i];
}
}
void calculateAverageTime(struct process proc[], int n)
{
int wt[n], tat[n], total_wt = 0, total_tat = 0;
findWaitingTime(proc, n, wt);
findTurnAroundTime(proc, n, wt, tat);
printf("\nProcesses Burst time Waiting time Turn around time\n");
15
for (int i = 0; i < n; i++)
{
total_wt += wt[i];
total_tat += tat[i];
printf(" %d \t\t %d \t\t %d \t\t %d\n", proc[i].pid, proc[i].bt, wt[i], tat[i]);
}
printf("\nAverage waiting time = %f", (float)total_wt / (float)n);
printf("\nAverage turn around time = %f\n", (float)total_tat / (float)n);
}
int main()
{
struct process proc[] = {{1, 6}, {2, 8}, {3, 7}, {4, 3}};
int n = sizeof proc / sizeof proc[0];
calculateAverageTime(proc, n);
return 0;
}
OUTPUT:
RESULT:
The program successfully executed, demonstrating FCFS scheduling by calculating and
displaying each process's waiting and turn-around times, along with the averages for all processes.
16
EX.NO : 03 (b)
CPU SCHEDULING ALGORITHMS - SJF
DATE :
AIM:
To implement a C program that schedules processes using the Shortest Job First (SJF) scheduling
algorithm, calculates, and displays the waiting time and turn-around time for each process, and computes
the average waiting and turn-around times.
ALGORITHM:
STEP 1: Start the program.
STEP 2: Define a structure for processes, including process ID (pid) and burst time (bt).
STEP 3: Sort the processes by burst time in ascending order using a comparison function and
qsort.
STEP 4: Calculate waiting times for all processes, initiating with zero for the first process and
summing up the burst times of all previous processes for the subsequent ones.
STEP 5: Calculate turn-around times for each process by adding its waiting time to its burst time.
STEP 6: Compute the average waiting time by dividing the sum of all waiting times by the
number of processes.
STEP 7: Compute the average turn-around time by dividing the sum of all turn-around times by
the number of processes.
STEP 8: Display the process ID, burst time, waiting time, and turn-around time for each process,
followed by the average waiting time and average turn-around time.
PROGRAM:
#include <stdio.h>
#include <stdlib.h>
// Define a structure for processes
struct process
{
int pid; // Process ID
int bt; // Burst Time
};
// Function to compare two processes by burst time for qsort
int compareByBurstTime(const void* a, const void* b)
{
struct process *p1 = (struct process*)a;
struct process *p2 = (struct process*)b;
return p1->bt > p2->bt;
}
void findWaitingTime(struct process proc[], int n, int wt[])
{
wt[0] = 0; // first process has no waiting time
for (int i = 1; i < n; i++)
{
wt[i] = proc[i-1].bt + wt[i-1];
17
}
}
void findTurnAroundTime(struct process proc[], int n, int wt[], int tat[])
{
for (int i = 0; i < n; i++)
{
tat[i] = proc[i].bt + wt[i];
}
}
void calculateAverageTime(struct process proc[], int n)
{
int wt[n], tat[n], total_wt = 0, total_tat = 0;
// Sort processes by burst time
qsort(proc, n, sizeof(struct process), compareByBurstTime);
findWaitingTime(proc, n, wt);
findTurnAroundTime(proc, n, wt, tat);
printf("\nProcesses Burst time Waiting time Turn around time\n");
for (int i = 0; i < n; i++)
{
total_wt += wt[i];
total_tat += tat[i];
printf(" %d \t\t %d \t\t %d \t\t %d\n", proc[i].pid, proc[i].bt, wt[i], tat[i]);
}
printf("\nAverage waiting time = %f", (float)total_wt / (float)n);
printf("\nAverage turn around time = %f\n", (float)total_tat / (float)n);
}
int main()
{
struct process proc[] = {{1, 6}, {2, 8}, {3, 7}, {4, 3}};
int n = sizeof proc / sizeof proc[0];
calculateAverageTime(proc, n);
return 0;
}
OUTPUT:
RESULT:
The program was executed successfully, applying the SJF scheduling algorithm.
18
EX.NO : 03 (c)
CPU SCHEDULING ALGORITHMS - SRTF
DATE :
AIM:
To develop a C program that schedules processes based on the Shortest Remaining Time First
(SRTF) scheduling algorithm.
ALGORITHM:
STEP 1: Start the program.
STEP 2: Define a structure for processes including process ID (pid), burst time (bt), and arrival
time (at).
STEP 3: Initialize remaining time array (rt[]) for all processes with their burst times.
STEP 4: Continue until all processes are completed:
• Find the process with the minimum remaining time that has arrived by the current time.
• Decrease its remaining time by one unit.
• If a process is completed, calculate its waiting time and mark it as completed by
incrementing the complete count.
STEP 5: Calculate turn-around time for each process as the sum of its burst time and waiting
time.
STEP 6: Calculate and display the average waiting time and average turn-around time for all
processes.
STEP 7: Display the process ID, burst time, arrival time, waiting time, turn-around time, and
completion time for each process.
STEP 8: End the program.
PROGRAM:
#include <stdio.h>
#include <limits.h>
struct process
{
int pid; // Process ID
int bt; // Burst Time
int at; // Arrival Time
};
// Function to find the waiting time for all processes
void findWaitingTime(struct process proc[], int n, int wt[])
{
int rt[n]; // Remaining time for all processes
for (int i = 0; i < n; i++)
rt[i] = proc[i].bt;
int complete = 0, t = 0, minm = INT_MAX;
int shortest = 0, finish_time;
int check = 0;
// Process until all processes gets completed
while (complete != n)
19
{
// Find process with minimum remaining time among the processes that arrives till the current time
for (int j = 0; j < n; j++)
{
if ((proc[j].at <= t) && (rt[j] < minm) && rt[j] > 0)
{
minm = rt[j];
shortest = j;
check = 1;
}
}
if (check == 0)
{
t++;
continue
}
// Reduce remaining time by one
rt[shortest]--;
// Update minimum
minm = rt[shortest];
if (minm == 0)
minm = INT_MAX;
// If a process gets completely executed
if (rt[shortest] == 0)
{
// Increment complete
complete++;
check = 0;
// Find finish time of current process
finish_time = t + 1;
// Calculate waiting time
wt[shortest] = finish_time - proc[shortest].bt - proc[shortest].at;
if (wt[shortest] < 0)
wt[shortest] = 0;
}
// Increment time
t++;
}
}
// Function to calculate turn around time
void findTurnAroundTime(struct process proc[], int n, int wt[], int tat[])
{
for (int i = 0; i < n; i++)
tat[i] = proc[i].bt + wt[i];
}
// Function to calculate average time
void calculateAverageTime(struct process proc[], int n)
20
{
int wt[n], tat[n], total_wt = 0, total_tat = 0;
findWaitingTime(proc, n, wt);
findTurnAroundTime(proc, n, wt, tat);
printf("\nProcess\tBurst Time\tArrival Time\tWaiting Time\tTurn-Around Time\tCompletion
Time\n");
for (int i = 0; i < n; i++)
{
total_wt += wt[i];
total_tat += tat[i];
int compl_time = tat[i] + proc[i].at;
printf("%d\t\t%d\t\t%d\t\t%d\t\t%d\t\t\t%d\n", proc[i].pid, proc[i].bt, proc[i].at, wt[i], tat[i],
compl_time);
}
printf("\nAverage waiting time = %f", (float)total_wt / (float)n);
printf("\nAverage turn around time = %f\n", (float)total_tat / (float)n);
}
int main()
{
struct process proc[] = {{1, 6, 1}, {2, 8, 1}, {3, 7, 2}, {4, 3, 3}};
int n = sizeof(proc) / sizeof(proc[0]);
calculateAverageTime(proc, n);
return 0;
}
OUTPUT:
RESULT:
The program was executed successfully, applying the SRTF scheduling algorithm.
21
EX.NO : 03 (d)
CPU SCHEDULING ALGORITHMS - PRIORITY
DATE :
AIM:
To create a C program that schedules processes using a Priority Scheduling algorithm.
ALGORITHM:
STEP 1: Start the program.
STEP 2: Define a structure for processes, including process ID (pid), burst time (bt), arrival time
(at), and priority.
STEP 3: Initialize remaining time array (rt[]) for all processes with their burst times.
STEP 4: If a process is completed, calculate its waiting time and mark it as completed by
incrementing the complete count.
STEP 5: Calculate turn-around time for each process as the sum of its burst time and waiting
time.
STEP 6: Calculate and display the average waiting time and average turn-around time for all
processes.
STEP 7: Display the process ID, burst time, arrival time, priority, waiting time, turn-around time
for each process.
PROGRAM:
#include <stdio.h>
#include <limits.h>
struct process
{
int pid; // Process ID
int bt; // Burst Time
int at; // Arrival Time
int priority; // Priority
};
// Function to find the waiting time for all processes
void findWaitingTime(struct process proc[], int n, int wt[])
{
int rt[n]; // Remaining time for all processes
for (int i = 0; i < n; i++)
rt[i] = proc[i].bt;
int complete = 0, t = 0;
int min_priority = INT_MAX;
int shortest = 0, finish_time;
int check = 0;
// Process until all processes gets completed
while (complete != n)
{
// Find process with minimum priority among the processes that arrives till the current time
for (int j = 0; j < n; j++)
22
{
if ((proc[j].at <= t) && (proc[j].priority < min_priority) && rt[j] > 0)
{
min_priority = proc[j].priority;
shortest = j;
check = 1;
}
}
if (check == 0)
{
t++;
continue;
}
// Reduce remaining time by one
rt[shortest]--;
// Update min_priority for the next iteration
if (rt[shortest] == 0) {
min_priority = INT_MAX;
}
// If a process gets completely executed
if (rt[shortest] == 0) {
// Increment complete
complete++;
check = 0;
// Find finish time of current process
finish_time = t + 1;
// Calculate waiting time
wt[shortest] = finish_time - proc[shortest].bt - proc[shortest].at;
if (wt[shortest] < 0)
wt[shortest] = 0;
}
// Increment time
t++;
}
}
// Function to calculate turn around time
void findTurnAroundTime(struct process proc[], int n, int wt[], int tat[])
{
for (int i = 0; i < n; i++)
tat[i] = proc[i].bt + wt[i];
}
// Function to calculate average time
void calculateAverageTime(struct process proc[], int n)
{
int wt[n], tat[n], total_wt = 0, total_tat = 0;
findWaitingTime(proc, n, wt);
findTurnAroundTime(proc, n, wt, tat);
23
printf("\nProcesses Burst time Arrival time Priority Waiting time Turnaround time\n");
for (int i = 0; i < n; i++)
{
total_wt += wt[i];
total_tat += tat[i];
printf("%d \t\t %d \t\t %d \t\t %d \t\t %d \t\t %d\n", proc[i].pid, proc[i].bt, proc[i].at,
proc[i].priority, wt[i], tat[i]);
}
printf("\nAverage waiting time = %f", (float)total_wt / (float)n);
printf("\nAverage turn around time = %f\n", (float)total_tat / (float)n);
}
int main()
{
struct process proc[] = {{1, 6, 1, 2}, {2, 8, 1, 1}, {3, 7, 2, 3}, {4, 3, 3, 4}};
int n = sizeof(proc) / sizeof(proc[0]);
calculateAverageTime(proc, n);
return 0;
}
OUTPUT:
RESULT:
The program successfully executed, demonstrating priority scheduling.
24
EX.NO : 03 (e)
CPU SCHEDULING ALGORITHMS – ROUND ROBIN
DATE :
AIM:
To create a C program that schedules processes using the Round Robin (RR) scheduling
algorithm
ALGORITHM:
STEP 1: Start the program.
STEP 2: Define a structure for processes including process ID (pid), original burst time (bt),
arrival time (at), and remaining time (rt).
STEP 3: Initialize an array to store the remaining burst times of all processes.
STEP 4: Implement the Round Robin scheduling by repeatedly traversing the processes and
reducing their remaining burst time by the quantum until all processes are completed.
STEP 5: Calculate waiting time for each process as the current time minus its burst time at the
moment it finishes.
STEP 6: Calculate turn-around time for each process as its burst time plus its waiting time.
STEP 7: Calculate and display the average waiting time and average turn-around time for all
processes.
STEP 8: Display the process ID, burst time, waiting time, and turn-around time for each process.
PROGRAM:
#include <stdio.h>
struct process
{
int pid; // Process ID
int bt; // Original Burst Time
int at; // Arrival Time
int rt; // Remaining Time
};
// Function to find the waiting time for all processes
void findWaitingTime(struct process proc[], int n, int quantum)
{
int rem_bt[n]; // Store remaining burst times.
for (int i = 0; i < n; i++)
rem_bt[i] = proc[i].bt;
int t = 0; // Current time
// Keep traversing processes in round robin manner until all of them are not done.
while (1)
{
int done = 1;
for (int i = 0; i < n; i++)
{
// If burst time of a process is greater than 0 then only need to process further
if (rem_bt[i] > 0) {
done = 0; // There is a pending process
25
if (rem_bt[i] > quantum)
{
// Increase the value of t i.e. shows how much time a process has been processed
t += quantum;
// Decrease the burst_time of current process by quantum
rem_bt[i] -= quantum;
}
// If burst time is smaller than or equal to quantum. Last cycle for this process.
else {
// Increase the value of t i.e. shows how much time a process has been processed
t = t + rem_bt[i];
// Waiting time is current time minus time used by this process
proc[i].rt = t - proc[i].bt;
// As the process gets fully executed make its remaining burst time = 0
rem_bt[i] = 0;
}
}
}
// If all processes are done
if (done == 1)
break;
}
}
// Function to calculate turn around time
void findTurnAroundTime(struct process proc[], int n)
{
// calculating turnaround time by adding bt[i] + wt[i]
for (int i = 0; i < n; i++)
proc[i].rt += proc[i].bt;
}
// Function to calculate average time
void calculateAverageTime(struct process proc[], int n, int quantum)
{
findWaitingTime(proc, n, quantum);
findTurnAroundTime(proc, n);
int total_wt = 0, total_tat = 0;
printf("\nProcess ID\tBurst Time\tWaiting Time\tTurnaround Time\n");
for (int i = 0; i < n; i++)
{
total_wt += proc[i].rt;
total_tat += proc[i].rt + proc[i].at;
printf("%d\t\t%d\t\t%d\t\t%d\n", proc[i].pid, proc[i].bt, proc[i].rt, proc[i].rt + proc[i].at);
}
printf("\nAverage waiting time = %f", (float)total_wt / n);
printf("\nAverage turnaround time = %f\n", (float)total_tat / n);
}
int main()
26
{
struct process proc[] = {{1, 6, 1}, {2, 8, 1}, {3, 7, 2}, {4, 3, 3}};
int n = sizeof(proc) / sizeof(proc[0]);
int quantum = 2; // Quantum time
calculateAverageTime(proc, n, quantum);
return 0;
}
OUTPUT:
DEPARTMENT OF IT
Preparation (Algorithm) 4
Observation (Program) 4
Results (Output) 4
Interpretation (Validation) 4
Viva-Voce 4
Total 20
RESULT:
The program successfully executed, demonstrating priority scheduling.
27
EX.NO : 04
INTERPROCESS COMMUNICATION
DATE :
AIM:
To develop a C program that demonstrates Inter-Process Communication (IPC) by using shared
memory and pipe mechanisms.
ALGORITHM:
STEP 1: Start the program.
STEP 2: Create a shared memory segment and a pipe for IPC.
STEP 3: Fork a child process from the parent process.
STEP 4: In the parent process, write a message to the shared memory and read the
acknowledgment from the pipe.
STEP 5: In the child process, read the message from the shared memory and send an
acknowledgment back through the pipe.
STEP 6: Close the pipe in both processes.
STEP 7: Detach and remove the shared memory segment.
STEP 8: Wait for the child process to complete if you are in the parent process.
PROGRAM:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <unistd.h>
int main()
{
int segment_id;
char* shared_memory;
const int size = 4096;
// Size of the shared memory segment
char* message = "Hello from Shared Memory!";
// Pipe file descriptor array
int pipefd[2];
if (pipe(pipefd) == -1)
{
perror("pipe");
exit(EXIT_FAILURE);
}
// Create the shared memory segment
segment_id = shmget(IPC_PRIVATE, size, S_IRUSR | S_IWUSR);
if (segment_id == -1)
{
perror("shmget");
28
exit(EXIT_FAILURE);
}
// Fork a child process
pid_t pid = fork();
if (pid == -1)
{
perror("fork");
exit(EXIT_FAILURE);
}
if (pid == 0)
{
// Child process
// Attach the shared memory segment
shared_memory = (char*) shmat(segment_id, NULL, 0);
if (shared_memory == (char *) -1)
{
perror("shmat");
exit(EXIT_FAILURE);
}
printf("Child reads: %s\n", shared_memory);
// Send confirmation back to parent through pipe
close(pipefd[0]); // Close unused read end
char* confirmation = "Message received via pipe!";
write(pipefd[1], confirmation, strlen(confirmation) + 1);
close(pipefd[1]);
// Detach the shared memory
shmdt(shared_memory);
}
else
{
// Parent process
// Attach and write to the shared memory segment
shared_memory = (char*) shmat(segment_id, NULL, 0);
strncpy(shared_memory, message, size);
printf("Parent wrote: %s\n", message);
// Wait for the child to process
wait(NULL);
// Read confirmation from child
close(pipefd[1]); // Close unused write end
char buffer[100];
read(pipefd[0], buffer, sizeof(buffer));
printf("Parent reads: %s\n", buffer);
close(pipefd[0]);
// Clean up shared memory
shmdt(shared_memory);
shmctl(segment_id, IPC_RMID, NULL);
}
29
return 0;
}
OUTPUT:
DEPARTMENT OF IT
Preparation (Algorithm) 4
Observation (Program) 4
Results (Output) 4
Interpretation (Validation) 4
Viva-Voce 4
Total 20
RESULT:
The program successfully executed, demonstrating inter process communication using shared
memory and pipes.
30
EX.NO : 05
PRODUCER - CONSUMER PROBLEM
DATE :
AIM:
To develop a C program that demonstrates Synchronization using producer-consumer problem.
ALGORITHM:
STEP 1: Start the program and include necessary libraries for threading and synchronization.
STEP 2: Define global variables for the buffer, its indices, and initialize synchronization
primitives: a mutex for mutual exclusion and semaphores for indicating full and empty states.
STEP 3: Implement the producer function to generate items, place them into the buffer, and use
semaphores and mutex to synchronize access.
STEP 4: Implement the consumer function to remove items from the buffer, also synchronized
with semaphores and mutex.
STEP 5: In the main function, initialize the mutex and semaphores, and create threads for both
producer and consumer roles.
STEP 6: Wait for both threads to complete their execution.
STEP 7: Clean up by destroying the mutex and semaphores.
PROGRAM:
#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define BUFFER_SIZE 5
int buffer[BUFFER_SIZE];
int in = 0;
int out = 0;
pthread_mutex_t mutex;
sem_t full, empty;
void* producer(void* param)
{
int item;
for (int i = 0; i < 10; i++)
{
sleep(rand() % 5);
item = rand() % 100; // Produce an item
sem_wait(&empty); // Decrement empty count
pthread_mutex_lock(&mutex);
buffer[in] = item;
in = (in + 1) % BUFFER_SIZE;
printf("Producer %ld produced %d\n", (long)param, item);
pthread_mutex_unlock(&mutex);
sem_post(&full); // Increment count of full slots
31
}
pthread_exit(0);
}
void* consumer(void* param)
{
int item;
for (int i = 0; i < 10; i++)
{
sleep(rand() % 5);
sem_wait(&full); // Decrement full count
pthread_mutex_lock(&mutex);
item = buffer[out];
out = (out + 1) % BUFFER_SIZE;
printf("Consumer %ld consumed %d\n", (long)param, item);
pthread_mutex_unlock(&mutex);
sem_post(&empty); // Increment count of empty slots
}
pthread_exit(0);
}
int main()
{
pthread_t tid[2]; // Thread identifiers
pthread_mutex_init(&mutex, NULL); // Initialize mutex
sem_init(&empty, 0, BUFFER_SIZE); // Initialize semaphores
sem_init(&full, 0, 0);
// Create producer and consumer threads
pthread_create(&tid[0], NULL, producer, (void*)1L);
pthread_create(&tid[1], NULL, consumer, (void*)2L);
// Wait for threads to finish
for (int i = 0; i < 2; i++)
{
pthread_join(tid[i], NULL);
}
// Clean up
pthread_mutex_destroy(&mutex);
sem_destroy(&empty);
sem_destroy(&full);
return 0;
}
32
OUTPUT:
DEPARTMENT OF IT
Preparation (Algorithm) 4
Observation (Program) 4
Results (Output) 4
Interpretation (Validation) 4
Viva-Voce 4
Total 20
RESULT:
The program successfully executed, demonstrating synchronization using producer consumer
problem.
33
EX.NO : 06
BANKER’S ALGORITHM
DATE :
AIM:
To develop a C program that implements the Banker's algorithm for deadlock avoidance.
ALGORITHM:
STEP 1: Start the program and include necessary libraries.
STEP 2: Define global arrays and variables for available resources, maximum demand, and
allocation.
STEP 3: Initialize these arrays with pre-defined values representing the state of the system.
STEP 4: Implement the Banker’s algorithm:
• Calculate the need by subtracting the allocation from the maximum demand for each
process.
• Check if the system is in a safe state by trying to find a sequence of processes whose
needs can be satisfied with current available resources.
• If such a sequence exists, the system is in a safe state.
STEP 5: Simulate resource request by processes and use the Banker's algorithm to decide if it's
safe to grant the request.
STEP 6: If the request can be safely granted, update the resource allocation and available
resources.
STEP 7: Print the output stating whether the initial state is safe, and if specific requests can be
granted.
PROGRAM:
#include <stdio.h>
#include <stdlib.h>
#define P 5 // Number of processes
#define R 3 // Number of resources
// Function declarations
int isSafe(int avail[], int max[][R], int alloc[][R], int need[][R]);
void calculateNeed(int need[P][R], int max[P][R], int alloc[P][R]);
int main()
{
int avail[R] = {3, 3, 2}; // Available instances of resources
int max[P][R] = {
{7, 5, 3},
{3, 2, 2},
{9, 0, 2},
{2, 2, 2},
{4, 3, 3}
}; // Maximum demand of each process
int alloc[P][R] = {
{0, 1, 0},
{2, 0, 0},
34
{3, 0, 2},
{2, 1, 1},
{0, 0, 2}
}; // Amount currently allocated
int need[P][R]; // Remaining needs of each process
calculateNeed(need, max, alloc);
int safe = isSafe(avail, max, alloc, need);
printf("System is %s\n", safe ? "in a safe state" : "not in a safe state");
return 0;
}
void calculateNeed(int need[P][R], int max[P][R], int alloc[P][R])
{
for (int i = 0; i < P; i++)
for (int j = 0; j < R; j++)
need[i][j] = max[i][j] - alloc[i][j];
}
int isSafe(int avail[R], int max[P][R], int alloc[P][R], int need[P][R])
{
int finish[P] = {0};
int safeSeq[P];
int work[R];
for (int i = 0; i < R; i++)
work[i] = avail[i];
int count = 0;
while (count < P)
{
int found = 0;
for (int p = 0; p < P; p++)
{
if (!finish[p])
{
int j;
for (j = 0; j < R; j++)
if (need[p][j] > work[j])
break;
if (j == R)
{
for (int k = 0; k < R; k++)
work[k] += alloc[p][k];
safeSeq[count++] = p;
finish[p] = 1;
found = 1;
}
}
}
if (!found)
{
35
printf("System is not in a safe state\n");
return 0;
}
}
printf("System is in a safe state.\nSafe sequence is: ");
for (int i = 0; i < P ; i++)
printf("%d ", safeSeq[i]);
printf("\n");
return 1;
}
OUTPUT:
DEPARTMENT OF IT
Preparation (Algorithm) 4
Observation (Program) 4
Results (Output) 4
Interpretation (Validation) 4
Viva-Voce 4
Total 20
RESULT:
The program successfully executed, demonstrating deadlock avoidance using the Banker's
algorithm. This ensures that the system is always in a safe state and avoids deadlocks effectively.
36
EX.NO : 07
PAGE REPLACEMENT ALGORITHMS
DATE :
AIM:
To develop a C program that implements the page replacement algorithms FIFO, Optimal, and
LRU.
ALGORITHM:
STEP 1: Start the program and include necessary libraries.
STEP 2: Define a structure for page frames and initialize an array representing the frames.
STEP 3: Implement FIFO Algorithm:
• Track the oldest frame for replacement.
• Replace the oldest frame when a page fault occurs.
STEP 4: Implement Optimal Algorithm: Predict the future requests to decide which frame to
replace, replacing the one not needed for the longest period.
STEP 5: Implement LRU Algorithm:
• Keep track of the least recently used frame by updating a counter every time a frame is
referenced.
• Replace the least recently used frame upon a page fault.
STEP 6: Simulate page requests and calculate the number of page faults for each algorithm.
STEP 7: Display the results.
PROGRAM:
#include <stdio.h>
#include <stdlib.h>
#define FRAME_SIZE 3
#define REF_LENGTH 9
int refs[REF_LENGTH] = {7, 0, 1, 2, 0, 3, 0, 4, 2}; // Example reference string
int frames[FRAME_SIZE];
int time[FRAME_SIZE]; // For LRU
void printFrames()
{
for (int i = 0; i < FRAME_SIZE; i++)
{
if (frames[i] == -1)
printf("_ ");
else
printf("%d ", frames[i]);
}
printf("\n");
}
int findLRU()
{
int i, minimum = time[0], pos = 0;
for (i = 1; i < FRAME_SIZE; i++)
37
{
if (time[i] < minimum)
{
minimum = time[i];
pos = i;
}
}
return pos;
}
int pageReplacementFIFO()
{
int i, pos = 0, faults = 0;
for (i = 0; i < FRAME_SIZE; i++) frames[i] = -1;
for (i = 0; i < REF_LENGTH; i++)
{
int found = 0;
for (int j = 0; j < FRAME_SIZE; j++)
{
if (frames[j] == refs[i])
{
found = 1;
break;
}
}
if (!found)
{
frames[pos] = refs[i];
pos = (pos + 1) % FRAME_SIZE;
faults++;
printFrames();
}
}
return faults;
}
int pageReplacementOptimal()
{
int i, j, pos, faults = 0, found;
for (i = 0; i < FRAME_SIZE; i++) frames[i] = -1;
for (i = 0; i < REF_LENGTH; i++)
{
found = 0;
for (j = 0; j < FRAME_SIZE; j++)
{
if (frames[j] == refs[i])
{
found = 1;
break;
38
}
}
if (!found)
{
if (i < FRAME_SIZE || frames[j] == -1)
{
frames[j] = refs[i];
}
else
{
int k, max, future[FRAME_SIZE];
for (j = 0; j < FRAME_SIZE; j++)
{
future[j] = 1000;
for (k = i + 1; k < REF_LENGTH; k++)
{
if (frames[j] == refs[k])
{
future[j] = k;
break;
}
}
}
max = future[0], pos = 0;
for (j = 1; j < FRAME_SIZE; j++)
{
if (future[j] > max)
{
max = future[j];
pos = j;
}
}
frames[pos] = refs[i];
}
faults++;
printFrames();
}
}
return faults;
}
int pageReplacementLRU()
{
int i, j, faults = 0, found, pos;
for (i = 0; i < FRAME_SIZE; i++)
{
frames[i] = -1;
39
time[i] = 0;
}
return 0;
}
40
OUTPUT:
DEPARTMENT OF IT
Preparation (Algorithm) 4
Observation (Program) 4
Results (Output) 4
Interpretation (Validation) 4
Viva-Voce 4
Total 20
RESULT:
The program successfully simulated and demonstrated the FIFO, Optimal, and LRU page
replacement algorithms, showing how each algorithm manages memory and handles page faults.
41
EX.NO : 08
DISK SCHEDULING ALGORITHMS
DATE :
AIM:
To develop a C program that implements the disk scheduling algorithms: FCFS, SSTF, SCAN,
and C-SCAN.
ALGORITHM:
STEP 1: Start the program and include necessary libraries.
STEP 2: Define global variables to store disk requests and the initial head position.
STEP 3: Implement FCFS Algorithm: Process requests in the order they appear in the queue.
STEP 4: Implement SSTF Algorithm: At each step, choose the request that is closest to the
current head position.
STEP 5: Implement SCAN Algorithm: Move the head towards the nearest end and then reverse
the direction when it reaches the end of the disk.
STEP 6: Implement C-SCAN Algorithm: Move the head from the current position to the end,
and then jump to the beginning and continue towards the initial start position.
STEP 7: Calculate the total head movement for each algorithm.
STEP 8: Display the results.
PROGRAM:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#define SIZE 8
int requests[SIZE] = {98, 183, 37, 122, 14, 124, 65, 67};
int head = 53;
void sort(int arr[], int n)
{
for (int i = 0; i < n - 1; i++)
for (int j = 0; j < n - i - 1; j++)
if (arr[j] > arr[j + 1])
{
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
int calculateTotalMovement(int req[], int n, int initialPos)
{
int totalMovement = 0;
int currentPos = initialPos;
for (int i = 0; i < n; i++)
{
totalMovement += abs(currentPos - req[i]);
42
currentPos = req[i];
}
return totalMovement;
}
void FCFS()
{
printf("FCFS Total Head Movement: %d\n", calculateTotalMovement(requests, SIZE, head));
}
void SSTF()
{
int done[SIZE] = {0}, totalMovement = 0, currentPos = head, closest, minDist, idx;
for (int i = 0; i < SIZE; i++)
{
minDist = INT_MAX;
for (int j = 0; j < SIZE; j++)
{
if (!done[j] && abs(currentPos - requests[j]) < minDist)
{
closest = requests[j];
minDist = abs(currentPos - requests[j]);
idx = j;
}
}
done[idx] = 1;
totalMovement += minDist;
currentPos = closest;
}
printf("SSTF Total Head Movement: %d\n", totalMovement);
}
void SCAN()
{
int totalMovement = 0, currentPos = head, largest = requests[0], smallest = requests[0];
int temp[SIZE + 1], n = 0;
for (int i = 0; i < SIZE; i++)
{
if (requests[i] > largest) largest = requests[i];
if (requests[i] < smallest) smallest = requests[i];
temp[n++] = requests[i];
}
temp[n++] = 0; // Adding 0 for scan to the end of disk
sort(temp, n);
int pos = 0;
while (pos < n && temp[pos] < currentPos) pos++;
for (int i = pos - 1; i >= 0; i--)
{
totalMovement += abs(currentPos - temp[i]);
currentPos = temp[i];
43
}
for (int i = pos; i < n; i++)
{
totalMovement += abs(currentPos - temp[i]);
currentPos = temp[i];
}
printf("SCAN Total Head Movement: %d\n", totalMovement);
}
void CSCAN()
{
int totalMovement = 0, currentPos = head, largest = requests[0], smallest = requests[0];
int temp[SIZE + 2], n = 0;
for (int i = 0; i < SIZE; i++)
{
if (requests[i] > largest) largest = requests[i];
if (requests[i] < smallest) smallest = requests[i];
temp[n++] = requests[i];
}
temp[n++] = 0; // Adding 0 for cscan to the end and start of disk
temp[n++] = 199; // Assuming disk size is 200
sort(temp, n);
int pos = 0;
while (pos < n && temp[pos] < currentPos) pos++;
for (int i = pos; i < n; i++)
{
totalMovement += abs(currentPos - temp[i]);
currentPos = temp[i];
}
for (int i = 0; i < pos; i++)
{
totalMovement += abs(currentPos - temp[i]);
currentPos = temp[i];
}
printf("CSCAN Total Head Movement: %d\n", totalMovement);
}
int main()
{
printf("Initial head position at %d\n", head);
FCFS();
SSTF();
SCAN();
CSCAN();
return 0;
}
44
OUTPUT:
DEPARTMENT OF IT
Preparation (Algorithm) 4
Observation (Program) 4
Results (Output) 4
Interpretation (Validation) 4
Viva-Voce 4
Total 20
RESULT:
The program successfully executed, demonstrating the FCFS, SSTF, SCAN, and C-SCAN disk
scheduling algorithms.
45
EX.NO : 09
FILE ORGANIZATION TECHNIQUES
DATE :
AIM:
To develop a C program that simulates the file organization techniques: Sequential, Random,
and Serial.
ALGORITHM:
STEP 1: Start the program and include necessary libraries.
STEP 2: Define structures for records and file storage.
STEP 3: Implement Sequential File Organization: Store and retrieve records in a sequential
manner.
STEP 4: Implement Random File Organization: Store records based on a hashing or direct
addressing scheme allowing direct access.
STEP 5: Implement Serial File Organization: Store records as they arrive without any specific
ordering, retrieve by reading all records.
STEP 6: Simulate insertion and retrieval of records for each technique.
STEP 7: Display the results.
PROGRAM:
#include <stdio.h>
#include <stdlib.h>
#define RECORDS 5
typedef struct
{
int key;
char data[20];
} Record;
Record database[RECORDS];
// Function to display records
void displayRecords()
{
for (int i = 0; i < RECORDS; i++)
{
printf("Record %d: Key = %d, Data = %s\n", i, database[i].key, database[i].data);
}
}
// Sequential insertion
void sequentialInsert()
{
for (int i = 0; i < RECORDS; i++)
{
database[i].key = i;
sprintf(database[i].data, "Data%d", i + 1);
}
46
}
// Random insertion based on a hash function
void randomInsert()
{
int index;
for (int i = 0; i < RECORDS; i++)
{
index = (i * 3) % RECORDS; // Simple hash function
database[index].key = i;
sprintf(database[index].data, "Data%d", i + 1);
}
}
// Serial insertion just like sequential but without sorting
void serialInsert()
{
for (int i = 0; i < RECORDS; i++)
{
database[i].key = i + 5; // Random keys to simulate serial insertion
sprintf(database[i].data, "Data%d", i + 1);
}
}
int main()
{
printf("Sequential File Organization:\n");
sequentialInsert();
displayRecords();
return 0;
}
47
OUTPUT:
DEPARTMENT OF IT
Preparation (Algorithm) 4
Observation (Program) 4
Results (Output) 4
Interpretation (Validation) 4
Viva-Voce 4
Total 20
RESULT:
The program successfully executed, demonstrating the different file organization techniques.
48
EX.NO : 10
FILE ALLOCATION STRATEGIES
DATE :
AIM:
To develop a C program that simulates the file allocation strategies: Sequential, Indexed, and
Linked.
ALGORITHM:
STEP 1: Start the program and include necessary libraries.
STEP 2: Define structures and arrays to simulate disk blocks.
STEP 3: Implement Sequential Allocation: Allocate contiguous blocks of disk to a file.
STEP 4: Implement Indexed Allocation: Use an index block that contains pointers to the actual
data blocks of the file.
STEP 5: Implement Linked Allocation: Each block points to the next block of the file, with the
last block pointing to a special value indicating the end of the file.
STEP 6: Simulate file creation and data retrieval for each strategy.
STEP 7: Display the results showing block allocations.
PROGRAM:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DISK_SIZE 10
#define INDEX_SIZE 3
int disk[DISK_SIZE] = {0}; // Simulating disk blocks, 0 means unallocated
void displayDisk()
{
for (int i = 0; i < DISK_SIZE; i++)
{
printf("%d ", disk[i]);
}
printf("\n");
}
// Sequential Allocation
void sequentialAllocation(int fileID, int fileSize)
{
printf("Sequential Allocation for File %d:\n", fileID);
for (int i = 0, allocated = 0; i < DISK_SIZE && allocated < fileSize; i++)
{
if (disk[i] == 0)
{
disk[i] = fileID;
allocated++;
}
}
49
displayDisk();
}
// Indexed Allocation
void indexedAllocation(int fileID, int blocks[])
{
printf("Indexed Allocation for File %d:\n", fileID);
int indexBlock = -1;
for (int i = 0; i < DISK_SIZE; i++)
{
if (disk[i] == 0)
{
indexBlock = i;
disk[i] = fileID; // Mark the index block
break;
}
}
if (indexBlock != -1)
{
for (int j = 0; j < INDEX_SIZE; j++)
{
if (blocks[j] < DISK_SIZE && disk[blocks[j]] == 0)
{
disk[blocks[j]] = fileID;
}
}
}
displayDisk();
}
// Linked Allocation
void linkedAllocation(int fileID, int start, int fileSize)
{
printf("Linked Allocation for File %d:\n", fileID);
int current = start;
for (int i = 0; i < fileSize; i++)
{
if (current < DISK_SIZE && disk[current] == 0)
{
disk[current] = fileID;
current = (current + 1) % DISK_SIZE; // Assuming circular list
}
}
displayDisk();
}
int main()
{
sequentialAllocation(1, 3);
int blocks[INDEX_SIZE] = {3, 4, 5};
50
indexedAllocation(2, blocks);
linkedAllocation(3, 6, 3);
return 0;
}
OUTPUT:
DEPARTMENT OF IT
Preparation (Algorithm) 4
Observation (Program) 4
Results (Output) 4
Interpretation (Validation) 4
Viva-Voce 4
Total 20
RESULT:
The program successfully executed, demonstrating different file allocation strategies.
51