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

OS LAB MANUAL

The document contains a lab file detailing experiments related to operating systems, focusing on Linux/Unix and DOS commands, process management, and CPU scheduling algorithms. It includes examples of basic commands, process creation using C programming, and implementations of scheduling algorithms such as FCFS and Shortest Job First. Additionally, it covers concepts like I/O redirection, piping, and process ID handling.

Uploaded by

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

OS LAB MANUAL

The document contains a lab file detailing experiments related to operating systems, focusing on Linux/Unix and DOS commands, process management, and CPU scheduling algorithms. It includes examples of basic commands, process creation using C programming, and implementations of scheduling algorithms such as FCFS and Shortest Job First. Additionally, it covers concepts like I/O redirection, piping, and process ID handling.

Uploaded by

mp796526
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 76

OS EXPERIMENTS LAB FILE

To: DR. SUNEET JOSHI

From: Manasvi Khare


EXPERIMENT 1
23BCE10232
Basic Linux/Unix Commands
 Aim: Study of OS commands

Comma
Slot: E11+E12+C14.
1. File Management Commands
Description
Example
nd

Date: 11/12/24
ls Lists files and directories. ls -l (detailed view).
cp Copies files or directories. cp file1.txt file2.txt.
mv Moves or renames files or mv file1.txt
directories. newname.txt.
rm Removes files or directories. rm file1.txt.
touch Creates an empty file. touch newfile.txt.

2. Process Management Commands


Comma Description Example
nd
Ps Displays currently running processes. ps -e (all processes).
Kill Terminates a process using its PID. kill 1234 (terminate process
1234).
Top Shows a dynamic list of running top (real-time updates).
processes.

3. Directory Navigation Commands


Comma Description Example
nd
cd Changes the current cd
directory. /home/user/Documents.
pwd Displays the current pwd.
directory.
mkdir Creates a new directory. mkdir newfolder.

3. I/O Redirection and piping

 > (Overwrite): Redirects output to a file, overwriting its content.


o Example: ls > filelist.txt
 >> (Append): Redirects output to a file, appending it without overwriting.
o Example: echo "Hello" >> filelist.txt
 < (Input Redirection): Provides input to a command from a file.
o Example: sort < unsorted.txt

2. Piping (|):

 Piping: Passes the output of one command as input to another.


o Example: ls | grep "txt" (filters files containing "txt").
 Chaining Multiple Commands:
o Example: cat filelist.txt | grep "txt" | sort (filters and sorts data).
 Combining with head/tail:
o Example: ps -e | head -n 10 (shows first 10 processes).

3. Redirecting Output and Errors:

 Redirect Both Output and Errors:


o Example: ls > output.txt 2>&1 (redirects both output and errors).

Common Symbols:
Symb Description Example

1
ol
> Redirect output (overwrite ls > filelist.txt
file).
>> Redirect output (append to echo "Hello" >> filelist.txt
file).
< Redirect input from a file. sort < unsorted.txt
` ` Pipe output of one command to
another.
2> Redirect error output. ls non_existent_file 2> error.txt

 Aim: Study of DOS commands

Command Description Type

mem Display memory on the system. External

Command to create a new


mkdir Internal
directory.

mklink Creates a symbolic link. Internal

Command to create a new


md Internal
directory.

chdir Changes directories. Internal

Check the hard drive running FAT


chkdsk External
for errors.

Check the hard drive running NTFS


chkntfs External
for errors.

Specify a listing of multiple options


choice External
within a batch file.

It Causes MS-DOS to look in other


append directories when editing a file or External
running a command.

Displays, adds and removes arp


arp External
information from network devices.

Assign a drive letter to an alternate


assign External
letter.

assoc View the file associations. Internal

Schedule a time to execute


at External
commands or programs.

2
Command Description Type

Recovery console command that


Recovery
batch executes several commands in a
Console
file.

Modify the boot configuration data


bcdedit External
store.

Recovery console command that


bootcfg allows a user to view, modify, and Recovery Console
rebuild the boot.ini file.

Enable and disable the Ctrl+C


break Internal
feature.

del Deletes one or more files. Internal

Recovery console command that


delete Internal
deletes a file.

Deletes one or more files or


deltree External
directories.

Recovery console command that


disable disables Windows system services Recovery Console
or drivers.

lock Lock the hard drive. Internal

 Features of MS-DOS Operating System


 It is a minimalist OS which means it can boot a computer and run programs.
 Still usable for simple tasks like word processing and playing games.
 The mouse cannot be used to give inputs instead it uses basic system
commands to perform the task.
 It is a 16-bit, free operating system.
 It is a single-user operating system.
 It is very lightweight due to fewer features available and no multitasking.

3
BELOW ARE SOME MORE COMMANDS FOR THE WINDOWS

4
5
EXPERIMENT 2
Process Creation and Management
 Aim: A program to create a clone.

Whenever a program gets a fork statement than at the same instance clone is created
and starts executing from there only, both the process is parent and child.

CODE:

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

int main(){
fork();
printf("HELLO WORLD -> My PID is %d\n",getpid());
return 0;
}

OUTPUT:

 Aim: Write a c program to create a new process using


fork

CODE:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main()
{

6
// create a new program
pid_t pid = fork();
// error handling

if (pid < 0)
{
// fork failed
printf("forkfailed");
return 1;
}
else if (pid == 0)
{
// child process
printf("child process\n");
printf("child process ID: %d\n", getpid());
printf("Parent process ID: %d\n", getppid());
}
else
{
// parent process
printf("parent process\n");
printf("parent process ID: %d\n", getpid());
printf("child process id: %d\n", pid);
}

return 0;
}

OUTPUT:

The fork system create a new process by duplicating the calling process after calling fork.

7
 Aim: Implement the parent-child process relationship
and demonstrate process termination.

CODE:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <sys/wait.h>
int main()
{
pid_t pid = fork();
if (pid < 0)
{
// fork failed
printf("forkfailed");
return 1;
}
else if (pid == 0)
{
// child process
printf("child process\n");
printf("child process ID: %d\n", getpid());
printf("Parent process ID: %d\n", getppid());
printf("child process will terminate now\n");
exit(0);
}

else
{
// parent process
printf("parent process\n");
printf("parent process ID: %d\n", getpid());
printf("waiting for child process to terminate...\n");

// wait for child process to terminate

int status;
wait(&status); // Wait for the child process to terminate

if (WIFEXITED(status))
{
printf("CHILD PROCESS TERMINATED WITH EXIT STATUS: %d\n",
WEXITSTATUS(status));
}
else
{
8
printf("Child process did not terminate successfully\n");
}
printf("Parent process will terminate now\n");
}

return 0;
}

OUTPUT:

 Terminates the child process after executing its block of code.


 The parent process wait for the child process to finish it also capture child process
exit status.
 It is a macro to check if the child process terminated properly.
 W exit status: refuse the exit status of the child process.

1. In this program the child process prints its PID and its parent’s PID then
terminates.
2. The parent process wait for the child to finish , checks its exit status and then
continues to its termination.

 Use exec() to replace a process image.


 exec() Function: Replaces the current process image with a new program. The
current process is replaced by the new one, and the process ID (PID) remains the
same.
 Process IDs (PID): Each process has a unique identifier. The parent can create child
processes using fork(), and the child can use getpid() to obtain its PID.
 Process Status Handling: The parent process can wait for the child process to finish
using wait(), and check the exit status with WIFEXITED() and WEXITSTATUS().

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

int main() {
pid_t pid = fork(); // Create a child process

if (pid < 0) {
9
// Error occurred
perror("fork failed");
return 1;
}

if (pid == 0) {
// Child process
printf("Child process: PID = %d\n", getpid());
execl("/bin/ls", "ls", "-l", NULL); // Replace current process with "ls" command
// This line will not be executed unless execl fails
printf("After exec()\n");
} else {
// Parent process
int status;
wait(&status); // Wait for the child to finish
if (WIFEXITED(status)) {
printf("Parent process: Child exited with status %d\n", WEXITSTATUS(status));
}
printf("Parent process: PID = %d\n", getpid());
}

return 0;
}

 Demonstrate the use of process IDs and status


handling.

In Unix-like systems, processes are identified by unique Process IDs (PIDs). The
parent process can create child processes using fork(), and the child process can
use getpid() to get its own PID. After a child process terminates, the parent can
use wait() to check the status of the child process, such as whether it exited
normally or if there was an error.

Here is an example demonstrating process IDs and status handling in C:

Key Functions:

 fork(): Creates a new child process. Returns 0 in the child process, and the child’s
PID in the parent.
 getpid(): Returns the PID of the calling process.
 wait(): Makes the parent process wait for the child to terminate and returns the
child's exit status.
 WIFEXITED(status): Checks if the child terminated normally.
 WEXITSTATUS(status): Retrieves the child's exit status.

CODE:

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>

int main() {
pid_t pid = fork(); // Create a child process

10
if (pid < 0) {
// Error occurred
perror("fork failed");
return 1;
}

if (pid == 0) {
// Child process
printf("Child process: PID = %d\n", getpid());
// Simulate some work
printf("Child process is doing work...\n");
_exit(0); // Exit the child process with status 0 (success)
} else {
// Parent process
int status;
wait(&status); // Wait for the child process to finish
printf("Parent process: PID = %d\n", getpid());

if (WIFEXITED(status)) {
// Check if the child exited normally
printf("Child exited with status %d\n", WEXITSTATUS(status));
} else {
printf("Child process did not exit normally\n");
}
}

return 0;
}

11
EXPERIMENT 3
CPU Scheduling Algorithms
1. AIM: WRITE A C PROGRAM TO STIMULTE FCFS(FIRST
COME FIRST SERVE) SCHEDULING ALGORITHM

CODE:

#include <stdio.h>

struct Process {
int id;
int arrivalTime;
int burstTime;
int waitingTime;
int turnaroundTime;
};

void findWaitingTime(struct Process proc[], int n) {


proc[0].waitingTime = 0; // First process has no waiting time

// Calculate waiting time for other processes


for (int i = 1; i < n; i++) {
proc[i].waitingTime = proc[i - 1].waitingTime + proc[i - 1].burstTime;
}
}

void findTurnaroundTime(struct Process proc[], int n) {


for (int i = 0; i < n; i++) {
proc[i].turnaroundTime = proc[i].burstTime + proc[i].waitingTime;
}
}

void findavgTime(struct Process proc[], int n) {


findWaitingTime(proc, n);
findTurnaroundTime(proc, n);

float totalWaitingTime = 0;
float totalTurnaroundTime = 0;

12
printf("\nProcess ID\tArrival Time\tBurst Time\tWaiting Time\tTurnaround Time\n");
for (int i = 0; i < n; i++) {
totalWaitingTime += proc[i].waitingTime;
totalTurnaroundTime += proc[i].turnaroundTime;
printf("%d\t\t%d\t\t%d\t\t%d\t\t%d\n",
proc[i].id, proc[i].arrivalTime, proc[i].burstTime,
proc[i].waitingTime, proc[i].turnaroundTime);
}
printf("\nAverage Waiting Time: %.2f", totalWaitingTime / n);
printf("\nAverage Turnaround Time: %.2f\n", totalTurnaroundTime / n);
}
int main() {
int n;
printf("Enter the number of processes: ");
scanf("%d", &n);
struct Process proc[n];

// Input process details


for (int i = 0; i < n; i++) {
proc[i].id = i + 1; // Assign process ID
printf("Enter Arrival Time and Burst Time for Process %d: ", proc[i].id);
scanf("%d %d", &proc[i].arrivalTime, &proc[i].burstTime);
}

// Sort processes by arrival time


for (int i = 0; i < n - 1; i++) {
for (int j = i + 1; j < n; j++) {
if (proc[i].arrivalTime > proc[j].arrivalTime) {
struct Process temp = proc[i];
proc[i] = proc[j];
proc[j] = temp;
}
}
}

findavgTime(proc, n);

return 0;
}

OUTPUT:

13
2. AIM: WRITE A C PROGRAM TO IMPLEMENT
SHORTEST JOB FIRST SCHEDULING WITH AND
WITHOUT PREEMTION

1.PREEMTIVE

CODE:

#include <stdio.h>

struct Process {
int id;
int arrivalTime;
int burstTime;
int remainingTime;
int waitingTime;
int turnaroundTime;
};

void findAvgTime(struct Process proc[], int n) {


int complete = 0, t = 0, minIndex;
float totalWaitingTime = 0;
float totalTurnaroundTime = 0;

14
while (complete < n) {
minIndex = -1;
int minBurst = 9999;

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


if (proc[i].arrivalTime <= t && proc[i].remainingTime > 0 &&
proc[i].remainingTime < minBurst) {
minBurst = proc[i].remainingTime;
minIndex = i;
}
}

if (minIndex != -1) {
proc[minIndex].remainingTime--;
t++;

if (proc[minIndex].remainingTime == 0) {
proc[minIndex].turnaroundTime = t - proc[minIndex].arrivalTime;
proc[minIndex].waitingTime = proc[minIndex].turnaroundTime -
proc[minIndex].burstTime;

totalWaitingTime += proc[minIndex].waitingTime;
totalTurnaroundTime += proc[minIndex].turnaroundTime;
complete++;
}
} else {
t++; // No process is ready, increment time
}
}

printf("\nProcess ID\tArrival Time\tBurst Time\tWaiting Time\tTurnaround Time\n");


for (int i = 0; i < n; i++) {
printf("%d\t\t%d\t\t%d\t\t%d\t\t%d\n",
proc[i].id, proc[i].arrivalTime, proc[i].burstTime,
proc[i].waitingTime, proc[i].turnaroundTime);
}

printf("\nAverage Waiting Time: %.2f", totalWaitingTime / n);


printf("\nAverage Turnaround Time: %.2f\n", totalTurnaroundTime / n);
}

void sortProcesses(struct Process proc[], int n) {


for (int i = 0; i < n - 1; i++) {
for (int j = i + 1; j < n; j++) {
if (proc[i].arrivalTime > proc[j].arrivalTime) {
struct Process temp = proc[i];
proc[i] = proc[j];
proc[j] = temp;
}
}
}
15
}

int main() {
int n;
printf("Enter the number of processes: ");
scanf("%d", &n);

struct Process proc[n];

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


proc[i].id = i + 1;
printf("Enter Arrival Time and Burst Time for Process %d: ", proc[i].id);
scanf("%d %d", &proc[i].arrivalTime, &proc[i].burstTime);
proc[i].remainingTime = proc[i].burstTime; // Initialize remaining time
}

sortProcesses(proc, n);
findAvgTime(proc, n);

return 0;
}

OUTPUT:

16
17
1. NON PREEMTIVE

CODE:

#include <stdio.h>

struct Process {
int id;
int arrivalTime;
int burstTime;
int waitingTime;
int turnaroundTime;
};

void findTurnaroundTime(struct Process proc[], int n) {


for (int i = 0; i < n; i++) {
proc[i].turnaroundTime = proc[i].burstTime + proc[i].waitingTime;
}
}

void findWaitingTime(struct Process proc[], int n) {


proc[0].waitingTime = 0; // First process has no waiting time
for (int i = 1; i < n; i++) {
proc[i].waitingTime = proc[i - 1].waitingTime + proc[i - 1].burstTime;
}
}

void findAvgTime(struct Process proc[], int n) {


findWaitingTime(proc, n);
findTurnaroundTime(proc, n);

float totalWaitingTime = 0;
float totalTurnaroundTime = 0;

printf("\nProcess ID\tArrival Time\tBurst Time\tWaiting Time\tTurnaround Time\n");


for (int i = 0; i < n; i++) {
totalWaitingTime += proc[i].waitingTime;
totalTurnaroundTime += proc[i].turnaroundTime;
printf("%d\t\t%d\t\t%d\t\t%d\t\t%d\n",
proc[i].id, proc[i].arrivalTime, proc[i].burstTime,
proc[i].waitingTime, proc[i].turnaroundTime);
}

printf("\nAverage Waiting Time: %.2f", totalWaitingTime / n);


printf("\nAverage Turnaround Time: %.2f\n", totalTurnaroundTime / n);
}

void sortProcesses(struct Process proc[], int n) {


for (int i = 0; i < n - 1; i++) {
18
for (int j = i + 1; j < n; j++) {
if (proc[i].arrivalTime > proc[j].arrivalTime) {
struct Process temp = proc[i];
proc[i] = proc[j];
proc[j] = temp;
}
}
}
}

int main() {
int n;
printf("Enter the number of processes: ");
scanf("%d", &n);

struct Process proc[n];

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


proc[i].id = i + 1;
printf("Enter Arrival Time and Burst Time for Process %d: ", proc[i].id);
scanf("%d %d", &proc[i].arrivalTime, &proc[i].burstTime);
}

sortProcesses(proc, n);
findAvgTime(proc, n);

return 0;
}

OUTPUT:

19
 AIM: WRITE A C PROGRAM TO STIMULATE RR(ROUND
ROBIN) ALGORITHM AND CALCULATE TURN AROUND
AND WAITING TIME

CODE:

#include <stdio.h>

struct Process {
int id;
int burstTime;
int remainingTime;
int waitingTime;
int turnaroundTime;
};

void findWaitingTime(struct Process proc[], int n, int timeQuantum) {


int remainingProcesses = n;
int time = 0;

while (remainingProcesses > 0) {


for (int i = 0; i < n; i++) {
if (proc[i].remainingTime > 0) {
if (proc[i].remainingTime > timeQuantum) {
time += timeQuantum;
proc[i].remainingTime -= timeQuantum;
} else {
time += proc[i].remainingTime;
proc[i].waitingTime = time - proc[i].burstTime; // Calculate waiting time
proc[i].turnaroundTime = time; // Calculate turnaround time
proc[i].remainingTime = 0; // Process completed
remainingProcesses--;
}
}
}
}
}

void findTurnaroundTime(struct Process proc[], int n) {


for (int i = 0; i < n; i++) {
proc[i].turnaroundTime = proc[i].waitingTime + proc[i].burstTime;
}
}

void findAvgTime(struct Process proc[], int n) {


float totalWaitingTime = 0;
float totalTurnaroundTime = 0;

20
printf("\nProcess ID\tBurst Time\tWaiting Time\tTurnaround Time\n");
for (int i = 0; i < n; i++) {
totalWaitingTime += proc[i].waitingTime;
totalTurnaroundTime += proc[i].turnaroundTime;
printf("%d\t\t%d\t\t%d\t\t%d\n",
proc[i].id, proc[i].burstTime,
proc[i].waitingTime, proc[i].turnaroundTime);
}

printf("\nAverage Waiting Time: %.2f", totalWaitingTime / n);


printf("\nAverage Turnaround Time: %.2f\n", totalTurnaroundTime / n);
}

int main() {
int n, timeQuantum;

printf("Enter the number of processes: ");


scanf("%d", &n);

struct Process proc[n];

// Input process details


for (int i = 0; i < n; i++) {
proc[i].id = i + 1; // Assign process ID
printf("Enter Burst Time for Process %d: ", proc[i].id);
scanf("%d", &proc[i].burstTime);
proc[i].remainingTime = proc[i].burstTime; // Initialize remaining time
}
printf("Enter Time Quantum: ");
scanf("%d", &timeQuantum);

findWaitingTime(proc, n, timeQuantum);
findAvgTime(proc, n);

return 0;
}

OUTPUT:

21
 AIM: WRITE A C PROGRAM TO IMPLEMENT PRIORITY
SCHEDULING AND TEST IT WITH DIFFERENT SETS OF
PRIORITIES

CODE:

#include <stdio.h>

struct Process {
int id;
int burstTime;
int waitingTime;
int turnaroundTime;
int priority;
};

void findTurnaroundTime(struct Process proc[], int n) {


for (int i = 0; i < n; i++) {
proc[i].turnaroundTime = proc[i].burstTime + proc[i].waitingTime;
}
}

void findWaitingTime(struct Process proc[], int n) {


// Sort processes based on priority
for (int i = 0; i < n - 1; i++) {
for (int j = i + 1; j < n; j++) {
if (proc[i].priority > proc[j].priority) {
struct Process temp = proc[i];
proc[i] = proc[j];
proc[j] = temp;
}
}
}

proc[0].waitingTime = 0; // First process has no waiting time


for (int i = 1; i < n; i++) {
proc[i].waitingTime = proc[i - 1].waitingTime + proc[i - 1].burstTime;
}
}

void findAvgTime(struct Process proc[], int n) {


findWaitingTime(proc, n);
findTurnaroundTime(proc, n);

float totalWaitingTime = 0;
float totalTurnaroundTime = 0;

printf("\nProcess ID\tBurst Time\tPriority\tWaiting Time\tTurnaround Time\n");


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

22
totalWaitingTime += proc[i].waitingTime;
totalTurnaroundTime += proc[i].turnaroundTime;
printf("%d\t\t%d\t\t%d\t\t%d\t\t%d\n",
proc[i].id, proc[i].burstTime, proc[i].priority,
proc[i].waitingTime, proc[i].turnaroundTime);
}

printf("\nAverage Waiting Time: %.2f", totalWaitingTime / n);


printf("\nAverage Turnaround Time: %.2f\n", totalTurnaroundTime / n);
}

int main() {
int n;

printf("Enter the number of processes: ");


scanf("%d", &n);

struct Process proc[n];

// Input process details


for (int i = 0; i < n; i++) {
proc[i].id = i + 1; // Assign process ID
printf("Enter Burst Time and Priority for Process %d: ", proc[i].id);
scanf("%d %d", &proc[i].burstTime, &proc[i].priority);
}

findAvgTime(proc, n);

return 0;
}

OUTPUT:

23
EXPERIMENT 4
Interprocess Communication (IPC)

Interprocess Communication (IPC) allows processes to


communicate and share data. There are several methods for IPC,
including pipes, shared memory, message queues,
and semaphores. Below is an overview of each IPC mechanism
with a code demonstration in C.

1)Write a program using pipes for IPC between parent and child
processes.

CODE:

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

int main() {
int pipefd[2];
pid_t pid;
char write_msg[] = "Hello from parent!";
char read_msg[100];

// Create a pipe
pipe(pipefd);

pid = fork();

if (pid < 0) {
perror("fork failed");
return 1;
}

if (pid == 0) {
// Child process - read from pipe
close(pipefd[1]); // Close the write end
read(pipefd[0], read_msg, sizeof(read_msg));
printf("Child received: %s\n", read_msg);
close(pipefd[0]);
} else {
// Parent process - write to pipe
close(pipefd[0]); // Close the read end
write(pipefd[1], write_msg, strlen(write_msg) + 1);
close(pipefd[1]);
}

return 0;
}

24
2. Shared Memory for Communication Between Multiple
Processes

Shared memory allows multiple processes to access the same memory


region to exchange data.

CODE:

#include <stdio.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <string.h>

int main() {
int shm_id;
char *shm_ptr;
char write_msg[] = "Shared memory communication!";

// Create shared memory segment


shm_id = shmget(IPC_PRIVATE, 1024, IPC_CREAT | 0666);
if (shm_id < 0) {
perror("shmget failed");
return 1;
}

// Attach the shared memory segment to the process


shm_ptr = shmat(shm_id, NULL, 0);
if (shm_ptr == (char *) -1) {
perror("shmat failed");
return 1;
}

// Write to the shared memory


strcpy(shm_ptr, write_msg);
printf("Written to shared memory: %s\n", shm_ptr);

// Detach and destroy shared memory


shmdt(shm_ptr);
shmctl(shm_id, IPC_RMID, NULL);

return 0;
}

25
3) Message Queues for Data Exchange Between
Processes

Message queues provide a way for processes to send and receive


messages in a first-in-first-out (FIFO) manner.

CODE:

#include <stdio.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>

struct message {
long msg_type;
char msg_text[100];
};

int main() {
key_t key = ftok("progfile", 65);
int msgid;
struct message msg;

// Create message queue


msgid = msgget(key, 0666 | IPC_CREAT);
if (msgid < 0) {
perror("msgget failed");
return 1;
}

// Send a message
msg.msg_type = 1;
strcpy(msg.msg_text, "Message Queue Communication!");
msgsnd(msgid, &msg, sizeof(msg), 0);
printf("Message Sent: %s\n", msg.msg_text);

// Receive a message
msgrcv(msgid, &msg, sizeof(msg), 1, 0);
printf("Message Received: %s\n", msg.msg_text);

// Destroy the message queue


msgctl(msgid, IPC_RMID, NULL);
26
return 0;
}

4. Semaphores for Synchronization Between Processes

Semaphores are synchronization tools used to control access to shared


resources by multiple processes.

CODE:

#include <stdio.h>
#include <semaphore.h>
#include <fcntl.h>
#include <unistd.h>

sem_t *sem;

int main() {
// Create a semaphore
sem = sem_open("/sem_example", O_CREAT, 0644, 1);
if (sem == SEM_FAILED) {
perror("sem_open failed");
return 1;
}

// Wait operation (decrement semaphore)


sem_wait(sem);

// Critical section
printf("Process in critical section\n");

// Signal operation (increment semaphore)


sem_post(sem);

// Close the semaphore


sem_close(sem);

// Unlink the semaphore


sem_unlink("/sem_example");

return 0;
}

27
EXPERIMENT 5
Thread Creation and Synchronization
Multithreading allows multiple threads (smaller units of a process)
to execute independently but share the same resources.
Multithreading can lead to performance improvements, but it also
introduces challenges such as race conditions. In this experiment,
we will use POSIX threads (pthreads) in C to create threads,
synchronize them using mutexes or semaphores, and resolve
issues like race conditions.

1. Create Multiple Threads Using POSIX Threads


(pthreads)

CODE:

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

void* print_message(void* thread_id) {


long tid = (long) thread_id;
printf("Hello from thread %ld\n", tid);
return NULL;
}

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

// Create 5 threads
for (t = 0; t < 5; t++) {
rc = pthread_create(&threads[t], NULL, print_message, (void*) t);
if (rc) {
printf("Error creating thread %ld\n", t);
return 1;
}
}

// Join threads to ensure they complete before the main thread ends
for (t = 0; t < 5; t++) {
pthread_join(threads[t], NULL);

28
}

return 0;
}

2. Implement Thread Synchronization Using Mutexes

In multithreading, when multiple threads try to access shared


resources, race conditions can occur. We can prevent this
using mutexes to ensure that only one thread accesses a resource at a
time

CODE:

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

pthread_mutex_t lock; // Mutex variable


int counter = 0;

void* increment_counter(void* arg) {


pthread_mutex_lock(&lock); // Lock the mutex
counter++;
printf("Thread %ld, Counter: %d\n", (long) arg, counter);
pthread_mutex_unlock(&lock); // Unlock the mutex
return NULL;
}

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

pthread_mutex_init(&lock, NULL); // Initialize the mutex

// Create 5 threads that increment the counter


for (t = 0; t < 5; t++) {
rc = pthread_create(&threads[t], NULL, increment_counter, (void*) t);
if (rc) {
printf("Error creating thread %ld\n", t);
return 1;
}
}

29
// Join threads to ensure they complete before the main thread ends
for (t = 0; t < 5; t++) {
pthread_join(threads[t], NULL);
}

pthread_mutex_destroy(&lock); // Destroy the mutex


return 0;
}

3. Demonstrate Race Conditions and Resolve Using


Locks

CODE:

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

int counter = 0;

void* increment_counter(void* arg) {


for (int i = 0; i < 100000; i++) {
counter++; // Race condition here
}
return NULL;
}

int main() {
pthread_t threads[5];
int rc;

// Create 5 threads
for (int t = 0; t < 5; t++) {
rc = pthread_create(&threads[t], NULL, increment_counter, NULL);
if (rc) {
printf("Error creating thread\n");
return 1;
}
}

// Join threads to ensure they complete before the main thread ends
for (int t = 0; t < 5; t++) {
pthread_join(threads[t], NULL);
}
30
printf("Counter value: %d\n", counter); // This might not be the expected value due to
race condition
return 0;
}

4. Simulate Producer-Consumer Problem Using


Multithreading

The producer-consumer problem is a classic synchronization


problem where one or more producer threads produce data and
place it into a buffer, while one or more consumer threads
consume data from the buffer. We can use mutexes and condition
variables to synchronize access to the shared buffer.

CODE:

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

#define BUFFER_SIZE 10
int buffer[BUFFER_SIZE];
int count = 0;

pthread_mutex_t mutex;
pthread_cond_t not_full;
pthread_cond_t not_empty;

void* producer(void* arg) {


while (1) {
pthread_mutex_lock(&mutex);
while (count == BUFFER_SIZE) { // Wait if buffer is full

31
pthread_cond_wait(&not_full, &mutex);
}
buffer[count++] = rand() % 100; // Produce a random number
printf("Produced: %d, Buffer size: %d\n", buffer[count - 1], count);
pthread_cond_signal(&not_empty); // Signal the consumer
pthread_mutex_unlock(&mutex);
sleep(1); // Simulate some work
}
return NULL;
}

void* consumer(void* arg) {


while (1) {
pthread_mutex_lock(&mutex);
while (count == 0) { // Wait if buffer is empty
pthread_cond_wait(&not_empty, &mutex);
}
int item = buffer[--count]; // Consume the item
printf("Consumed: %d, Buffer size: %d\n", item, count);
pthread_cond_signal(&not_full); // Signal the producer
pthread_mutex_unlock(&mutex);
sleep(1); // Simulate some work
}
return NULL;
}

int main() {
pthread_t producer_thread, consumer_thread;
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&not_full, NULL);
pthread_cond_init(&not_empty, NULL);

// Create producer and consumer threads


pthread_create(&producer_thread, NULL, producer, NULL);
pthread_create(&consumer_thread, NULL, consumer, NULL);

// Join threads (though they will run indefinitely)


pthread_join(producer_thread, NULL);
pthread_join(consumer_thread, NULL);

pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&not_full);
pthread_cond_destroy(&not_empty);
return 0;
}

32
EXPERIMENT 6
Deadlock Detection and Prevention

1. Simulate a System with Multiple Resources and


Processes

CODE:

#include <stdio.h>

#define P 5 // Number of processes


#define R 3 // Number of resources

// Function to print the system's status


void print_state(int processes[], int available[], int allocation[][R], int max[][R], int need[]
[R]) {
printf("Processes: ");
for (int i = 0; i < P; i++) {
printf("P%d ", processes[i]);
}
printf("\nResources: ");
for (int j = 0; j < R; j++) {
printf("R%d ", available[j]);
}
printf("\n");
}

// Function to check if the system is in a safe state using Banker's Algorithm


int is_safe(int available[], int allocation[][R], int max[][R], int need[][R]) {
int finish[P] = {0};
int work[R];
33
for (int i = 0; i < R; i++) {
work[i] = available[i];
}

while (1) {
int progress_made = 0;
for (int i = 0; i < P; i++) {
if (!finish[i]) {
int can_allocate = 1;
for (int j = 0; j < R; j++) {
if (need[i][j] > work[j]) {
can_allocate = 0;
break;
}
}
if (can_allocate) {
for (int j = 0; j < R; j++) {
work[j] += allocation[i][j];
}
finish[i] = 1;
progress_made = 1;
}
}
}
if (!progress_made) {
break;
}
}

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


if (!finish[i]) {
return 0; // Not in a safe state
}
}
return 1; // Safe state
}

int main() {
int processes[] = {0, 1, 2, 3, 4}; // Process IDs
int available[] = {3, 3, 2}; // Available resources

int allocation[P][R] = {
{0, 1, 0},
{2, 0, 0},
{3, 0, 3},
{2, 1, 1},
{0, 0, 2}
};

int max[P][R] = {
{7, 5, 3},
{3, 2, 2},
{9, 0, 2},
{2, 2, 2},
{4, 3, 3}
};

int need[P][R]; // Need = Max - Allocation


for (int i = 0; i < P; i++) {
34
for (int j = 0; j < R; j++) {
need[i][j] = max[i][j] - allocation[i][j];
}
}

// Print current state


print_state(processes, available, allocation, max, need);

if (is_safe(available, allocation, max, need)) {


printf("The system is in a safe state.\n");
} else {
printf("The system is not in a safe state.\n");
}

return 0;
}

2. Implement Banker's Algorithm for Deadlock


Avoidance

The Banker's Algorithm ensures that the system will never enter an
unsafe state by evaluating resource allocation requests and verifying if
they will lead to a deadlock. The algorithm avoids deadlock by ensuring
the system is always in a safe state.

Key steps of Banker's Algorithm:

1. Check if a request can be granted by comparing the process's need


with the available resources.
2. If the request is safe, grant the request and check if the system
stays in a safe state.
3. If the system is not in a safe state after granting a request, deny it
and wait.

3. Deadlock Detection Using Resource Allocation Graph


(RAG)

A Resource Allocation Graph (RAG) is a directed graph where:

 Processes are represented by nodes.


 Resources are represented by nodes.
 An edge from a process to a resource indicates that the process is
requesting that resource.
 An edge from a resource to a process indicates that the resource is
allocated to the process.

A deadlock exists if there is a cycle in the resource allocation graph.


35
CODE:

#include <stdio.h>

#define P 5 // Number of processes


#define R 3 // Number of resources

int allocation[P][R] = {{0, 1, 0}, {2, 0, 0}, {3, 0, 3}, {2, 1, 1}, {0, 0, 2}};
int request[P][R] = {{1, 0, 2}, {1, 0, 0}, {0, 1, 1}, {1, 1, 0}, {0, 0, 1}};
int available[R] = {3, 3, 2};

int safe_state() {
int finish[P] = {0}; // To track processes that have finished
int work[R];
for (int i = 0; i < R; i++) {
work[i] = available[i];
}

while (1) {
int progress = 0;
for (int i = 0; i < P; i++) {
if (!finish[i]) {
int can_allocate = 1;
for (int j = 0; j < R; j++) {
if (request[i][j] > work[j]) {
can_allocate = 0;
break;
}
}
if (can_allocate) {
for (int j = 0; j < R; j++) {
work[j] += allocation[i][j];
}
finish[i] = 1;
progress = 1;
}
}
}
if (!progress) {
break;
}
}

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


if (!finish[i]) {
return 0; // Deadlock detected
}
}
return 1; // Safe state
}

int main() {
if (safe_state()) {
printf("The system is in a safe state.\n");
} else {
printf("Deadlock detected.\n");
}

return 0;
36
}

4. Analyzing Deadlock and Ways to Resolve It


Scenario:

Consider the following system with 3 processes and 2 resources:

 Available resources: 1 unit of resource A, 1 unit of resource B.


 Process 1 holds 1 unit of resource A and is requesting 1 unit of
resource B.
 Process 2 holds 1 unit of resource B and is requesting 1 unit of
resource A.

Here, both processes are waiting for the other to release a resource,
leading to a deadlock.

Resolution:

To resolve the deadlock, we can:

1. Preempt resources: Temporarily take resources away from one


process to allow others to finish.
2. Abort processes: Terminate one or more processes to break the
cycle.

EXPERIMENT 7
Memory Management Techniques

1. Simulate Paging and Segmentation

Paging:

Paging is a memory management scheme that eliminates the need for


contiguous allocation of physical memory. It divides the physical memory
into fixed-size blocks called frames and divides logical memory into
blocks of the same size, called pages.

CODE:

#include <stdio.h>

#define PAGE_SIZE 4 // Number of pages


#define FRAME_SIZE 4 // Number of frames

37
// Function to simulate paging
void simulate_paging(int pages[], int num_pages, int frames[], int num_frames) {
int page_faults = 0;

// Initialize frames to -1 (empty)


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

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


int page = pages[i];
int page_found = 0;

// Check if the page is already in memory (in one of the frames)


for (int j = 0; j < num_frames; j++) {
if (frames[j] == page) {
page_found = 1;
break;
}
}

// If page is not found, replace a frame


if (!page_found) {
page_faults++;
frames[i % num_frames] = page; // Simple replacement for demonstration
}

// Print the current state of frames


printf("Page %d: ", page);
for (int j = 0; j < num_frames; j++) {
printf("%d ", frames[j]);
}
printf("\n");
}

printf("Total Page Faults: %d\n", page_faults);


}

int main() {
int pages[] = {0, 1, 2, 3, 0, 1, 2, 4, 5, 6}; // Reference string of pages
int num_pages = sizeof(pages) / sizeof(pages[0]);
int frames[FRAME_SIZE]; // Frame array to hold pages in memory

simulate_paging(pages, num_pages, frames, FRAME_SIZE);

return 0;
}

38
 Segmentation:

Segmentation is a memory management technique where the memory is


divided into segments based on the logical divisions of a program, such as
code, data, and stack. Each segment can have different sizes.

CODE:

#include <stdio.h>

#define MAX_SEGMENTS 5

// Function to simulate segmentation


void simulate_segmentation(int segments[], int num_segments) {
int segment_faults = 0;

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


int segment = segments[i];
// Simulate a segment fault if segment is not allocated
if (segment == -1) {
segment_faults++;
printf("Segment %d not found, segment fault occurred.\n", i);
}
else {
printf("Segment %d found: %d\n", i, segment);
}
}

printf("Total Segment Faults: %d\n", segment_faults);


}

int main() {
int segments[] = {10, -1, 20, 30, -1}; // Example segment table (use -1 for
unallocated)

39
int num_segments = sizeof(segments) / sizeof(segments[0]);

simulate_segmentation(segments, num_segments);

return 0;
}

2. Implement Page Replacement Algorithms

Page replacement algorithms are used to manage the content of pages in


memory when the memory is full and a new page needs to be loaded.

FIFO (First-In-First-Out):

FIFO replaces the page that has been in memory the longest.

FIFO Algorithm in C:

CODE:

#include <stdio.h>

#define FRAME_SIZE 4

void fifo(int pages[], int num_pages, int frames[], int num_frames) {


int page_faults = 0, index = 0;
for (int i = 0; i < num_pages; i++) {
int page = pages[i];
int page_found = 0;

// Check if the page is already in memory


for (int j = 0; j < num_frames; j++) {
if (frames[j] == page) {
page_found = 1;
break;
40
}
}

// If the page is not found in frames, replace the oldest page


if (!page_found) {
frames[index] = page;
index = (index + 1) % num_frames;
page_faults++;
}

// Print current frame state


printf("Page %d: ", page);
for (int j = 0; j < num_frames; j++) {
printf("%d ", frames[j]);
}
printf("\n");
}

printf("Total Page Faults: %d\n", page_faults);


}

int main() {
int pages[] = {0, 1, 2, 3, 0, 1, 2, 4, 5, 6};
int num_pages = sizeof(pages) / sizeof(pages[0]);
int frames[FRAME_SIZE] = {-1, -1, -1, -1};

fifo(pages, num_pages, frames, FRAME_SIZE);

return 0;
}

 LRU (Least Recently Used):

LRU replaces the page that has not been used for the longest period.

CODE:

#include <stdio.h>

41
#define FRAME_SIZE 4

void lru(int pages[], int num_pages, int frames[], int num_frames) {


int page_faults = 0;
int time[FRAME_SIZE] = {-1, -1, -1, -1}; // Tracks last used time of frames

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


int page = pages[i];
int page_found = 0;

// Check if page is already in memory


for (int j = 0; j < num_frames; j++) {
if (frames[j] == page) {
page_found = 1;
break;
}
}

// If page is not found, replace the least recently used page


if (!page_found) {
int min_time = time[0];
int min_index = 0;
for (int j = 1; j < num_frames; j++) {
if (time[j] < min_time) {
min_time = time[j];
min_index = j;
}
}

frames[min_index] = page;
page_faults++;
}

// Update last used time for the current page


for (int j = 0; j < num_frames; j++) {
if (frames[j] == page) {
time[j] = i;
break;
}
}

// Print the current frame state


printf("Page %d: ", page);
for (int j = 0; j < num_frames; j++) {
printf("%d ", frames[j]);
}
printf("\n");
}

printf("Total Page Faults: %d\n", page_faults);


}

int main() {
int pages[] = {0, 1, 2, 3, 0, 1, 2, 4, 5, 6};
int num_pages = sizeof(pages) / sizeof(pages[0]);
int frames[FRAME_SIZE] = {-1, -1, -1, -1};

lru(pages, num_pages, frames, FRAME_SIZE);

42
return 0;
}

3. Simulate Memory Allocation Algorithms

CODE:

#include <stdio.h>

#define BLOCKS 5 // Number of memory blocks


#define PROCESSES 3 // Number of processes

// Function to implement First Fit


void first_fit(int blocks[], int processes[], int n, int m) {
for (int i = 0; i < n; i++) {
int placed = 0;
for (int j = 0; j < m; j++) {
if (blocks[j] >= processes[i]) {
blocks[j] -= processes[i];
printf("Process %d allocated to block %d\n", i + 1, j + 1);
placed = 1;
break;
}
}
if (!placed) {
printf("Process %d could not be allocated\n", i + 1);
}
}
}

int main() {
int blocks[BLOCKS] = {10, 20, 30, 40, 50}; // Memory blocks
int processes[PROCESSES] = {5, 10, 15}; // Process sizes

printf("First Fit Allocation:\n");


first_fit(blocks, processes, PROCESSES, BLOCKS);

43
return 0;
}

EXPERIMENT 8
File System Implementation

44
1)Write a program to simulate the creation, deletion,
and manipulation of files in a
directory.
we need to implement basic file system operations like creating, deleting,
and manipulating files within a directory. This would involve:
 Create File: Add a new file to the directory, storing its name, size,
and allocation information.
 Delete File: Remove a file from the directory and free up the
allocated space.
 Manipulate File: Perform file operations such as renaming,
reading, or writing (this can be simulated using file metadata).

CODE:

#include <stdio.h>
#include <string.h>

#define MAX_FILES 10
#define MAX_NAME_LENGTH 50

// Structure for file


struct File {
char name[MAX_NAME_LENGTH];
int size;
int location; // For simplicity, use an index to represent location
};

// Structure for directory


struct Directory {
struct File files[MAX_FILES];
int fileCount;
};

// Initialize directory
void initDirectory(struct Directory *dir) {
dir->fileCount = 0;
}

// Create a file
void createFile(struct Directory *dir, char *name, int size) {
if (dir->fileCount < MAX_FILES) {
strcpy(dir->files[dir->fileCount].name, name);
dir->files[dir->fileCount].size = size;
dir->files[dir->fileCount].location = dir->fileCount; // Location =
index in directory
dir->fileCount++;
printf("File '%s' created.\n", name);
45
} else {
printf("Directory full. Cannot create more files.\n");
}
}

// Delete a file
void deleteFile(struct Directory *dir, char *name) {
for (int i = 0; i < dir->fileCount; i++) {
if (strcmp(dir->files[i].name, name) == 0) {
for (int j = i; j < dir->fileCount - 1; j++) {
dir->files[j] = dir->files[j + 1];
}
dir->fileCount--;
printf("File '%s' deleted.\n", name);
return;
}
}
printf("File '%s' not found.\n", name);
}

// List files in the directory


void listFiles(struct Directory *dir) {
if (dir->fileCount == 0) {
printf("Directory is empty.\n");
return;
}
for (int i = 0; i < dir->fileCount; i++) {
printf("File: %s, Size: %d, Location: %d\n", dir->files[i].name, dir-
>files[i].size, dir->files[i].location);
}
}

int main() {
struct Directory dir;
initDirectory(&dir);

createFile(&dir, "file1.txt", 100);


createFile(&dir, "file2.txt", 200);
listFiles(&dir);

deleteFile(&dir, "file1.txt");
listFiles(&dir);

return 0;
}

46
2) Implement file allocation methods (Contiguous,
Linked, Indexed).
File allocation methods

 Contagious

CODE:

#include <stdio.h>
#include <string.h>

#define MAX_DISK_SIZE 10

struct File {
char name[50];
int size;
int location;
};

struct ContiguousAllocation {
int disk[MAX_DISK_SIZE];
};

void allocateContiguous(struct ContiguousAllocation *alloc, struct File


*file, int startBlock) {
if (startBlock + file->size <= MAX_DISK_SIZE) {
for (int i = startBlock; i < startBlock + file->size; i++) {
alloc->disk[i] = 1; // Mark block as occupied
}
47
file->location = startBlock;
printf("File '%s' allocated from block %d to %d.\n", file->name,
startBlock, startBlock + file->size - 1);
} else {
printf("Not enough space for allocation.\n");
}
}

int main() {
int location[MAX_DISK_SIZE]; // Array to store the linked block locations
};

struct LinkedAllocation {
int disk[MAX_DISK_SIZE]; // 0: free, 1: occupied
};

// Function to allocate linked blocks to a file


void allocateLinked(struct LinkedAllocation *alloc, struct File *file) {
int blockCount = 0;
int *lastBlock = NULL;

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


if (alloc->disk[i] == 0) { // Free block found
alloc->disk[i] = 1; // Mark the block as occupied

// Store the block index in the location array


file->location[blockCount++] = i;

// If this is not the first block, link it to the previous one


if (blockCount > 1) {
alloc->disk[file->location[blockCount - 2]] = i; // Link previous
block to current
}

// Check if the required number of blocks is allocated


if (blockCount == file->size) {
alloc->disk[file->location[blockCount - 1]] = -1; // Mark end of
linked list
printf("File '%s' allocated with linked blocks: ", file->name);
for (int j = 0; j < file->size; j++) {
printf("%d ", file->location[j]);
}
printf("\n");
return;
}
}
}
printf("Not enough space for linked allocation.\n");
}
48
int main() {
struct LinkedAllocation alloc = {0}; // Initialize all disk blocks to 0 (free)
struct File file = {"file1.txt", 3, {-1}}; // Initialize location to -1

allocateLinked(&alloc, &file);

return 0;
}
struct ContiguousAllocation alloc = {0};
struct File file = {"file1.txt", 3, -1};

allocateContiguous(&alloc, &file, 2);

return 0;
}

 Linked

CODE:

#include <stdio.h>
#include <string.h>

#define MAX_DISK_SIZE 10

struct File {
char name[50];
int size;

49
 Indexed

CODE:

#include <stdio.h>
#include <string.h>

#define MAX_DISK_SIZE 10

struct File {
char name[50];
int size;
int location[MAX_DISK_SIZE]; // Store block locations directly in an
array
};

struct IndexedAllocation {
int disk[MAX_DISK_SIZE];
int index[MAX_DISK_SIZE]; // Index block for file
};

// Function to allocate indexed blocks to a file


void allocateIndexed(struct IndexedAllocation *alloc, struct File *file) {
int availableBlocks = 0;
for (int i = 0; i < MAX_DISK_SIZE; i++) {
if (alloc->disk[i] == 0) { // Check if block is free
alloc->index[availableBlocks++] = i; // Add block to index
alloc->disk[i] = 1; // Mark block as occupied
}
if (availableBlocks == file->size) { // Once enough blocks are found
// Store the index of the allocated blocks in the file's location
for (int j = 0; j < file->size; j++) {
file->location[j] = alloc->index[j];
}
printf("File '%s' allocated using indexed blocks: ", file->name);
for (int j = 0; j < file->size; j++) {
printf("%d ", file->location[j]);

50
}
printf("\n");
return;
}
}
printf("Not enough space for indexed allocation.\n");
}

int main() {
struct IndexedAllocation alloc = {0};
struct File file = {"file1.txt", 3, {-1}}; // Initialize file location to -1

allocateIndexed(&alloc, &file);

return 0;
}

3)Simulate disk scheduling algorithms (FCFS, SSTF,


SCAN, C-SCAN).
 FCFS

CODE:

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

void fcfs(int requests[], int n, int initial_position) {


int seek_count = 0;
int current_position = initial_position;

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


seek_count += abs(requests[i] - current_position);
current_position = requests[i];
}
printf("Total seek count: %d\n", seek_count);
}

int main() {
int requests[] = {15, 34, 8, 12, 21};
51
int n = sizeof(requests) / sizeof(requests[0]);
int initial_position = 10;

fcfs(requests, n, initial_position);

return 0;
}

 SSTF

CODE:

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

void sstf(int requests[], int n, int initial_position) {


int seek_count = 0;
int current_position = initial_position;
int visited[n];
for (int i = 0; i < n; i++) visited[i] = 0;

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


int min_dist = 1000000;
int index = -1;
for (int j = 0; j < n; j++) {
if (!visited[j] && abs(requests[j] - current_position) < min_dist) {
min_dist = abs(requests[j] - current_position);
index = j;
}
}
visited[index] = 1;
seek_count += min_dist;
current_position = requests[index];
}

printf("Total seek count: %d\n", seek_count);


}

int main() {
int requests[] = {15, 34, 8, 12, 21};

52
int n = sizeof(requests) / sizeof(requests[0]);
int initial_position = 10;

sstf(requests, n, initial_position);

return 0;
}

4. SCAN

CODE:

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

void scan(int requests[], int n, int initial_position, int disk_size) {


int seek_count = 0;
int current_position = initial_position;

int left[n], right[n];


int left_count = 0, right_count = 0;

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


if (requests[i] < current_position)
left[left_count++] = requests[i];
else
right[right_count++] = requests[i];
}

// Sort left and right


for (int i = 0; i < left_count - 1; i++) {
for (int j = 0; j < left_count - i - 1; j++) {
if (left[j] < left[j + 1]) {
int temp = left[j];
left[j] = left[j + 1];
left[j + 1] = temp;
53
}
}
}
for (int i = 0; i < right_count - 1; i++) {
for (int j = 0; j < right_count - i - 1; j++) {
if (right[j] > right[j + 1]) {
int temp = right[j];
right[j] = right[j + 1];
right[j + 1] = temp;
}
}
}

// Process the requests


for (int i = 0; i < left_count; i++) {
seek_count += abs(current_position - left[i]);
current_position = left[i];
}
seek_count += abs(current_position - 0);
current_position = 0;
for (int i = 0; i < right_count; i++) {
seek_count += abs(current_position - right[i]);
current_position = right[i];
}

printf("Total seek count: %d\n", seek_count);


}

int main() {
int requests[] = {15, 34, 8, 12, 21};
int n = sizeof(requests) / sizeof(requests[0]);
int initial_position = 10;
int disk_size = 50;

scan(requests, n, initial_position, disk_size);

return 0;
}

54
5. CSCAN

CODE:

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

void cscan(int requests[], int n, int initial_position, int disk_size) {


int seek_count = 0;
int current_position = initial_position;

int left[n], right[n];


int left_count = 0, right_count = 0;

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


if (requests[i] < current_position)
left[left_count++] = requests[i];
else
right[right_count++] = requests[i];
}

// Sort left and right


for (int i = 0; i < left_count - 1; i++) {
for (int j = 0; j < left_count - i - 1; j++) {
if (left[j] < left[j + 1]) {
int temp = left[j];
left[j] = left[j + 1];
left[j + 1] = temp;
}
}
}
for (int i = 0; i < right_count - 1; i++) {
for (int j = 0; j < right_count - i - 1; j++) {
if (right[j] > right[j + 1]) {
int temp = right[j];
right[j] = right[j + 1];
right[j + 1] = temp;
}
}
}

55
// Process the requests
for (int i = 0; i < right_count; i++) {
seek_count += abs(current_position - right[i]);
current_position = right[i];
}
seek_count += abs(current_position - (disk_size - 1));
current_position = disk_size - 1;
for (int i = 0; i < left_count; i++) {
seek_count += abs(current_position - left[i]);
current_position = left[i];
}

printf("Total seek count: %d\n", seek_count);


}

int main() {
int requests[] = {15, 34, 8, 12, 21};
int n = sizeof(requests) / sizeof(requests[0]);
int initial_position = 10;
int disk_size = 50;

cscan(requests, n, initial_position, disk_size);

return 0;
}

56
EXPERIMENT 9
Virtual Memory Management
1. Simulate Virtual Memory using Paging

In this simulation, the virtual memory is divided into fixed-size pages, and
the physical memory is divided into fixed-size frames. The program
manages page allocation and simulates the process of accessing virtual
memory.

CODE;

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

#define FRAME_SIZE 4 // Number of frames in physical memory


#define PAGE_SIZE 4 // Number of pages in the virtual memory

void simulate_virtual_memory(int reference_string[], int n) {


int frames[FRAME_SIZE] = {-1, -1, -1, -1}; // Initially, frames are empty
int page_faults = 0;

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


int page = reference_string[i];
int found = 0;

// Check if the page is already in memory (frame)


for (int j = 0; j < FRAME_SIZE; j++) {
if (frames[j] == page) {
found = 1;
break;
}
}

// If page is not found, it’s a page fault


if (!found) {
page_faults++;
// Find an empty frame or replace the first one
57
int replaced = 0;
for (int j = 0; j < FRAME_SIZE; j++) {
if (frames[j] == -1) {
frames[j] = page;
replaced = 1;
break;
}
}

if (!replaced) {
// Replace the first frame if no empty frame
for (int j = 0; j < FRAME_SIZE - 1; j++) {
frames[j] = frames[j + 1];
}
frames[FRAME_SIZE - 1] = page;
}
}

// Print current frame state


printf("Frames: ");
for (int j = 0; j < FRAME_SIZE; j++) {
printf("%d ", frames[j]);
}
printf("\n");
}

printf("Total page faults: %d\n", page_faults);


}

int main() {
int reference_string[] = {0, 1, 2, 3, 0, 4, 2, 1, 3, 0, 4};
int n = sizeof(reference_string) / sizeof(reference_string[0]);

simulate_virtual_memory(reference_string, n);

return 0;
}

58
2. Demand Paging Concept

CODE:

#include <stdio.h>

#define NUM_PAGES 4
#define FRAME_SIZE 4

void demand_paging(int reference_string[], int n) {


int frames[FRAME_SIZE] = {-1, -1, -1, -1}; // Empty frames
int page_faults = 0;

printf("Demand Paging Simulation:\n");

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


int page = reference_string[i];
int found = 0;

// Check if page is already in frames


for (int j = 0; j < FRAME_SIZE; j++) {
if (frames[j] == page) {
found = 1;
break;
}
59
}

if (!found) {
page_faults++;
// Load page into an empty frame or replace the least recently
used
int replaced = 0;
for (int j = 0; j < FRAME_SIZE; j++) {
if (frames[j] == -1) {
frames[j] = page;
replaced = 1;
break;
}
}

if (!replaced) {
// Replace the first frame
for (int j = 0; j < FRAME_SIZE - 1; j++) {
frames[j] = frames[j + 1];
}
frames[FRAME_SIZE - 1] = page;
}
}

// Print current state of frames


printf("Frames: ");
for (int j = 0; j < FRAME_SIZE; j++) {
printf("%d ", frames[j]);
}
printf("\n");
}

printf("Total page faults: %d\n", page_faults);


}

int main() {
int reference_string[] = {0, 1, 2, 3, 0, 4, 2, 1, 3, 0, 4};
int n = sizeof(reference_string) / sizeof(reference_string[0]);

demand_paging(reference_string, n);

return 0;
}

60
3. Simulate Page Replacement Policies (FIFO, LRU)

Page replacement algorithms are crucial for managing which pages to


keep in memory when there are more pages than available memory. We'll
implement FIFO (First In, First Out) and LRU (Least Recently
Used) algorithms.

CODE:

#include <stdio.h>

#define FRAME_SIZE 4

void fifo_page_replacement(int reference_string[], int n) {

int frames[FRAME_SIZE] = {-1, -1, -1, -1}; // Empty frames

int page_faults = 0;

int queue[FRAME_SIZE] = {0}; // Queue to track page order for FIFO

int front = 0, rear = 0;

printf("FIFO Page Replacement:\n");

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

int page = reference_string[i];

int found = 0;

// Check if page is already in frames

for (int j = 0; j < FRAME_SIZE; j++) {

if (frames[j] == page) {

found = 1;

break;

if (!found) {

page_faults++;

// If there's an empty frame, place the page

if (rear < FRAME_SIZE) {

frames[rear] = page;

rear++;

} else {

// Replace the oldest page

frames[front] = page;

front = (front + 1) % FRAME_SIZE;

// Print current state of frames

printf("Frames: ");

for (int j = 0; j < FRAME_SIZE; j++) {

printf("%d ", frames[j]);


62
}

printf("\n");

printf("Total page faults: %d\n", page_faults);

int main() {

int reference_string[] = {0, 1, 2, 3, 0, 4, 2, 1, 3, 0, 4};

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

fifo_page_replacement(reference_string, n);

return 0;

 LRU Page Replacement:

CODE:

63
#include <stdio.h>

#define FRAME_SIZE 4

void lru_page_replacement(int reference_string[], int n) {

int frames[FRAME_SIZE] = {-1, -1, -1, -1}; // Empty frames

int page_faults = 0;

printf("LRU Page Replacement:\n");

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

int page = reference_string[i];

int found = 0;

int least_recently_used = -1;

// Check if page is already in frames and track LRU

for (int j = 0; j < FRAME_SIZE; j++) {

if (frames[j] == page) {

found = 1;

least_recently_used = j;

break;

if (!found) {

page_faults++;

// Find the least recently used page to replace

int lru_index = -1;

for (int j = 0; j < FRAME_SIZE; j++) {

if (frames[j] == -1) {

lru_index = j;
64
break;

if (lru_index == -1) {

lru_index = least_recently_used;

frames[lru_index] = page;

// Print current state of frames

printf("Frames: ");

for (int j = 0; j < FRAME_SIZE; j++) {

printf("%d ", frames[j]);

printf("\n");

printf("Total page faults: %d\n", page_faults);

int main() {

int reference_string[] = {0, 1, 2, 3, 0, 4, 2, 1, 3, 0, 4};

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

lru_page_replacement(reference_string, n);

return 0;

65
4.Implement a program to track page faults during
process execution.

CODE:

#include <stdio.h>

#define FRAME_SIZE 4 // Number of frames in physical memory

#define NUM_PAGES 11 // Number of pages in reference string

// Function to simulate page faults using FIFO page replacement

void fifo_page_faults(int reference_string[], int n) {

int frames[FRAME_SIZE] = {-1, -1, -1, -1}; // Initially empty frames

int page_faults = 0;

printf("FIFO Page Fault Simulation:\n");

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

int page = reference_string[i];

int found = 0;

// Check if the page is already in one of the frames (no page fault)

for (int j = 0; j < FRAME_SIZE; j++) {

if (frames[j] == page) {

found = 1;

break;

// If page is not found, it's a page fault

if (!found) {

page_faults++;

// If there's an empty frame, place the page there

int replaced = 0;

for (int j = 0; j < FRAME_SIZE; j++) {

if (frames[j] == -1) {

frames[j] = page;

replaced = 1;

break;

// If all frames are full, replace the oldest page

if (!replaced) {

for (int j = 0; j < FRAME_SIZE - 1; j++) {


67
frames[j] = frames[j + 1];

frames[FRAME_SIZE - 1] = page;

// Print current frame state

printf("Reference: %d -> Frames: ", page);

for (int j = 0; j < FRAME_SIZE; j++) {

printf("%d ", frames[j]);

printf("\n");

printf("Total page faults: %d\n", page_faults);

int main() {

int reference_string[] = {0, 1, 2, 3, 0, 4, 2, 1, 3, 0, 4};

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

fifo_page_faults(reference_string, n);

return 0;

OUTPUT:

68
EXPERIMENT 10
Disk Scheduling Algorithms

1. First-Come-First-Served (FCFS) Disk Scheduling

FCFS is the simplest disk scheduling algorithm where the disk accesses
requests in the order they arrive, without any reordering. It is non-
preemptive and doesn't optimize for disk seek time.

CODE:

#include <stdio.h>

void fcfs_disk_scheduling(int requests[], int num_requests, int start) {


69
int total_seek_time = 0;
int current_position = start;

printf("Disk Scheduling using FCFS\n");


printf("Initial position: %d\n", start);

// Process each request in order


for (int i = 0; i < num_requests; i++) {
int request = requests[i];
int seek_time = abs(request - current_position); // Calculate seek time
total_seek_time += seek_time; // Accumulate total seek time
current_position = request; // Update current position
printf("Move to: %d, Seek Time: %d\n", request, seek_time);
}

printf("Total Seek Time: %d\n", total_seek_time);


}

int main() {
int requests[] = {98, 183, 41, 122, 14, 124, 65, 67}; // Disk I/O requests
int num_requests = sizeof(requests) / sizeof(requests[0]);
int start = 53; // Initial position of the disk arm

fcfs_disk_scheduling(requests, num_requests, start);

return 0;
}

2. Shortest Seek Time First (SSTF) Disk Scheduling

SSTF selects the request that is closest to the current disk head position.
It minimizes the seek time for each request but can lead to starvation if
some requests are far from the current position.

CODE:

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

void sstf_disk_scheduling(int requests[], int num_requests, int start) {


int total_seek_time = 0;
int current_position = start;
int visited[num_requests]; // Array to track visited requests
for (int i = 0; i < num_requests; i++) visited[i] = 0;

printf("Disk Scheduling using SSTF\n");


70
printf("Initial position: %d\n", start);

// Process each request based on the shortest seek time


for (int count = 0; count < num_requests; count++) {
int min_seek_time = __INT_MAX__;
int closest_request = -1;

// Find the closest unvisited request


for (int i = 0; i < num_requests; i++) {
if (!visited[i]) {
int seek_time = abs(requests[i] - current_position);
if (seek_time < min_seek_time) {
min_seek_time = seek_time;
closest_request = i;
}
}
}

// Mark the closest request as visited


visited[closest_request] = 1;
total_seek_time += min_seek_time; // Add seek time
current_position = requests[closest_request]; // Move to the request
printf("Move to: %d, Seek Time: %d\n", current_position, min_seek_time);
}

printf("Total Seek Time: %d\n", total_seek_time);


}

int main() {
int requests[] = {98, 183, 41, 122, 14, 124, 65, 67}; // Disk I/O requests
int num_requests = sizeof(requests) / sizeof(requests[0]);
int start = 53; // Initial position of the disk arm

sstf_disk_scheduling(requests, num_requests, start);

return 0;
}

71
3. SCAN Disk Scheduling

CODE:

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

void scan_disk_scheduling(int requests[], int num_requests, int start, int disk_size) {


int total_seek_time = 0;
int current_position = start;
int direction = 1; // 1 for right, -1 for left

// Sort the requests array


for (int i = 0; i < num_requests - 1; i++) {
for (int j = 0; j < num_requests - i - 1; j++) {
if (requests[j] > requests[j + 1]) {
int temp = requests[j];
requests[j] = requests[j + 1];
requests[j + 1] = temp;
}
}
}

printf("Disk Scheduling using SCAN\n");


printf("Initial position: %d, Direction: %d\n", start, direction);

// Service requests in the current direction


for (int i = 0; i < num_requests; i++) {
if (requests[i] >= start) {
int seek_time = abs(requests[i] - current_position);
total_seek_time += seek_time;
current_position = requests[i];
printf("Move to: %d, Seek Time: %d\n", current_position, seek_time);
}
}

// Reverse direction
printf("Reverse direction...\n");
for (int i = num_requests - 1; i >= 0; i--) {
if (requests[i] < start) {
int seek_time = abs(requests[i] - current_position);
total_seek_time += seek_time;
current_position = requests[i];
printf("Move to: %d, Seek Time: %d\n", current_position, seek_time);
}
}

printf("Total Seek Time: %d\n", total_seek_time);


}

int main() {
int requests[] = {98, 183, 41, 122, 14, 124, 65, 67}; // Disk I/O requests
int num_requests = sizeof(requests) / sizeof(requests[0]);
int start = 53; // Initial position of the disk arm
72
int disk_size = 200; // Maximum size of the disk

scan_disk_scheduling(requests, num_requests, start, disk_size);

return 0;
}

4. C-SCAN (Circular SCAN) Disk Scheduling

C-SCAN is similar to SCAN, but instead of reversing direction, once the


disk arm reaches the end, it jumps back to the beginning and starts
servicing requests in the same direction.

C Program for C-SCAN Disk Scheduling:

CODE:

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

void cscan_disk_scheduling(int requests[], int num_requests, int start, int disk_size) {


int total_seek_time = 0;
73
int current_position = start;

// Sort the requests array


for (int i = 0; i < num_requests - 1; i++) {
for (int j = 0; j < num_requests - i - 1; j++) {
if (requests[j] > requests[j + 1]) {
int temp = requests[j];
requests[j] = requests[j + 1];
requests[j + 1] = temp;
}
}
}

printf("Disk Scheduling using C-SCAN\n");


printf("Initial position: %d\n", start);

// Service requests in one direction (right)


for (int i = 0; i < num_requests; i++) {
if (requests[i] >= start) {
int seek_time = abs(requests[i] - current_position);
total_seek_time += seek_time;
current_position = requests[i];
printf("Move to: %d, Seek Time: %d\n", current_position, seek_time);
}
}

// Jump to the beginning of the disk (circular)


total_seek_time += abs(disk_size - 1 - current_position); // Seek to the end
current_position = 0; // Jump back to the beginning
printf("Jump to the beginning, Seek Time: %d\n", abs(disk_size - 1 - current_position));

// Service remaining requests in the same direction


for (int i = 0; i < num_requests; i++) {
if (requests[i] < start) {
int seek_time = abs(requests[i] - current_position);
total_seek_time += seek_time;
current_position = requests[i];
printf("Move to: %d, Seek Time: %d\n", current_position, seek_time);
}
}

printf("Total Seek Time: %d\n", total_seek_time);


}

int main() {
int requests[] = {98, 183, 41, 122, 14, 124, 65, 67}; // Disk I/O requests
int num_requests = sizeof(requests) / sizeof(requests[0]);
int start = 53; // Initial position of the disk arm
int disk_size = 200; // Maximum size of the disk

cscan_disk_scheduling(requests, num_requests, start, disk_size);

return 0;
}

74
S

75

You might also like