0% found this document useful (0 votes)
15 views64 pages

OSrecdwithout Output

The document outlines the objectives and outcomes of the Operating Systems Laboratory course at Muffakham Jah College of Engineering & Technology. It details practical exercises involving CPU scheduling algorithms, semaphores, memory management, and file management system calls using C in a Linux environment. Additionally, it provides basic commands for file and directory management in UNIX, along with example C programs demonstrating system calls and process management concepts.

Uploaded by

mohdkashif6305
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
15 views64 pages

OSrecdwithout Output

The document outlines the objectives and outcomes of the Operating Systems Laboratory course at Muffakham Jah College of Engineering & Technology. It details practical exercises involving CPU scheduling algorithms, semaphores, memory management, and file management system calls using C in a Linux environment. Additionally, it provides basic commands for file and directory management in UNIX, along with example C programs demonstrating system calls and process management concepts.

Uploaded by

mohdkashif6305
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 64

MUFFAKHAM JAH COLLEGE OF ENGINEERING & TECHNOLOGY

( Sultan - ul - Uloom Educational Society )

OPERATING SYSTEMS LABORATORY(PC 452 CS)

OBJECTIVE

This lab complements the operating systems course. Students will gain practical experience with
designing and implementing concepts of operating systems such as
1. Learn different types of CPU scheduling algorithms.
2. Demonstrate the usage of semaphores for solving synchronization problem.
3. Understand memory management techniques and different types of fragmentation.
4. That occur in them and various page replacement policies.
5. Understand Banker‘s algorithm used for deadlock avoidance.
6. Learn various disk scheduling algorithms.
using C language in Linux environment.

OUTCOMES
Upon the completion of Operating Systems practical course, the student will be able to:

Student will be able to


 Evaluate the performance of different types of CPU scheduling algorithms.
 Implement producer-consumer problem, reader-writers problem, Dining
philosopher’s problem.
 Simulate Banker’s algorithm for deadlock avoidance.
 Implement paging replacement and disk scheduling techniques.
 Use different system calls for writing application programs.

1
BASIC COMMANDS:

1. Date Command :
This command is used to display the current data and time.
$date
2. Calender Command :
This command is used to display the calendar of the year or the particular month of
calendar year.
Syntax :
a. $cal <year>
b. $cal <month> <year>
Here the first syntax gives the entire calendar for given year & the second Syntax gives
the calendar of reserved month of that year.
3. Echo Command :
This command is used to print the arguments on the screen .
Syntax : $echo <text>
4. ’who’ Command :
It is used to display who are the users connected to our computer currently.
Syntax : $who
5. ’who am i’ Command :
Display the details of the current working directory.
Syntax : $who am i
6. ’CLEAR’ Command :
It is used to clear the screen.
Syntax : $clear
7. ’MAN’ Command :
It help us to know about the particular command and its options & working. It is like
„help‟ command in windows .
Syntax : $man <command name>
8. LIST Command :
It is used to list all the contents in the current working directory.
Syntax : $ ls – options <arguments>
If the command does not contain any argument means it is working in the Current directory.

2
Options :
a– used to list all the files including the hidden files.
c– list all the files columnwise.
d- list all the directories.
m- list the files separated by commas.
p- list files include „/‟ to all the directories.
r- list the files in reverse alphabetical order.
f- list the files based on the list modification date.
x-list in column wise sorted order.

DIRECTORY RELATED COMMANDS :

1. Present Working Directory Command :


To print the complete path of the current working directory.
Syntax : $pwd
2. MKDIR Command :
To create or make a new directory in a current directory .
Syntax : $mkdir <directory name>
3. CD Command :
To change or move the directory to the mentioned directory .
Syntax : $cd <directory name>.
4. RMDIR Command :
To remove a directory in the current directory & not the current directory itself.
Syntax : $rmdir <directory name>

FILE RELATED COMMANDS :

1. CREATE A FILE :
To create a new file in the current directory we use CAT command.
Syntax : $cat > <filename>
The > symbol is redirectory we use cat command.
2. DISPLAY A FILE :
To display the content of file mentioned we use CAT command without „>‟ operator.
Syntax : $cat <filename>
Options –s = to neglect the warning /error message.

3
3. Concatinate two files :
$cat file1 file2 >file3 /*Concatenate file1 and file2 to file3 */
4. SORTING A FILE :
To sort the contents in alphabetical order in reverse order.
Syntax :
$sort <filename >
Option : $ sort –r <filename>
5. copying contents from one file to another :
To copy the contents from source to destination file . so that both contents are same.
Syntax :
$cp <source filename> <destination filename>
$cp <source filename path > <destination filename path>
Wen both are ordinary files, the first is copied into second. If destination file doesn’t exit, it will
be created before copying takes places. If it does exit, it will simply be overwritten without any
warning from the system.
6. MOVE Command :
To completely move the contents from source file to destination file and to remove the source file.
When both are ordinary files, the first is moved into second.
If destination file doesn’t exit , it will be created before copying takes place.
If it does exit, it will simply be overwritten without any warning from system
Syntax :
$ mv <source filename> <destination filename>
On execution of this command FileName1 no longer exit at its original location, but the
contents of FileName1 is moved to FileName2.
7. REMOVE Command :
To permanently remove the file we use this command .
Syntax :
$rm <filename>
8. WORD Command :
To list the content count of no of lines , words, characters .
Syntax :
$wc<filename>

4
Options :
-c – to display no of characters.
-l – to display only the lines.
-w – to display the no of words.
FILTERS AND PIPES
HEAD : It is used to display the top ten lines of file.
Syntax: $head<filename>
TAIL : This command is used to display the last ten lines of file.
Syntax: $tail<filename>

5
EXPERIMENT 1
OBJECTIVE
Write a C programs to implement UNIX system calls
(a) fork() (b)sleep() ( c)wait() (d)execv() (e)execlp()

DESCRIPTION: system callsork (): The fork function creates a copy of the running process. The
copy ( the child) has a copy of parent process stack, data area, heap and starts after fork statement.
The fork function is available in unistd.h

 wait (): The wait function suspends the execution of current process until a child has exited
or until a signal is delivered whose action is to terminate the current process.

 sleep (): It suspends the execution of a process for a specified amount of time.

 getpid (): This function returns the ID of the process from where it is called.

 getppid (): This function returns the ID of the parent’s process from where it is called.

(a) AIM : To demonstrate usage of fork(), System calls

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

int main()
{
pid_t p;
p = fork();
if (p == 0)
{
printf("I am child having PID %d\n", getpid());
printf("My parent PID is %d\n", getppid());
}
else
{
printf("I am parent having PID %d\n", getpid());
printf("My child PID is %d\n", p);
}

return 0;
}

6
Compile:
Run:
Output:

(b) AIM : To demonstrate usage of sleep() System calls

#include<stdio.h>
#include<unistd.h>
int main()
{
pid_t ret_value;
printf(“\n The process id is %d\n”,getpid());
ret_value=fork();
if(ret_value<0)
{
//fork has failed
printf(“\n Fork Failure\n”);
}
elseif(ret_value==0)
{
//child process
sleep(20);
printf(“\n child process\n”);
printf(“the process id is %d\n”,getpid());
else
{
//parent process
printf(“parent process\n”);
printf(“the process id is %d\n”,getpid());
}
return 0;
}
Compile:
Run:
Output:

7
(c )AIM : To demonstrate usage of wait() System calls

#include<stdio.h>
#include<unistd.h>
int main()
{
pid_t ret_value;
printf(“\n The process id is %d\n”,getpid());
ret_value=fork();
if(ret_value<0)
{
//fork has failed
printf(“\n Fork Failure\n”);
}
elseif(ret_value==0)
{
//child process
printf(“\n child process\n”);
printf(“the process id is %d\n”,getpid());
else
{
//parent process
wait();
printf(“parent process\n”);
printf(“the process id is %d\n”,getpid());
}
return 0;
}

Compile:
Run:
Output:

8
DESCRIPTION: exec system call

 execl (): This function initiates a new program in the same environment in which it is
operating. An executable program with fully qualified path, i.e, /bin/ls and arguments are
passed to the function.

 execlp (): The routine execlp () will perform the same routine except that it will use
environment variable path to determine which is executable to process. Thus, a fully
qualified name would not have to be used. The first argument to the function could be “ls”.
This function can also take the fully qualified name as it also resolves explicitly.

 execv (): This is same as exec () except that the arguments are passed as null terminated
array of pointers to char. The first element “argv[0]” is the command name.

 execvp (): The routine execvp () will perform the same purpose except that it will use
environment variable path to determine which is executable to process. The first argument
to the function could be “ls”. This function can also take the fully qualified name as it also
resolves explicitly.

( d)AIM: Program to implement execv system calls

#include<stdio.h>
#include<unistd.h>
main()
{
char *temp[3];
temp[0]="ls";
temp[1]="-l";
temp[2]=(char *)0;
execv("/bin/ls",temp);
printf("this will not print\n");
}
Compile:
Run:
Output:

9
(e)AIM: Program to implement execlp function

#include<stdio.h>
#include<sys/types.h>
main()
{
int pid;
pid=fork();
if(pid==0)
{
printf("\n fork program started");
execlp("/bin/ls","ls",NULL);
}
else
{
printf("\nend");
}
}

Compile:
Run:
Output:

10
EXPERIMENT 2
OBJECTIVE
Write a C programs to implement file management system calls

DESCRIPTION:
The file structure related system calls available in the UNIX system let us create, open, and
close files, read and write files, randomly access files, alias and remove files, get information
about files, check the accessibility of files, change protections, owner, and group of files, and
control devices. These operations either use a character string that defines the absolute or relative
path name of a file, or a small integer called a file descriptor

System Calls Used: open(), creat(), read(), write(), close()


open() : system call to open a file :open returns a file descriptor, an integer specifying the
position of this open file in the table of open files for the current process .
close() : system call to close a file
read() : read data from a file opened for reading
write() : write data to a file opened for writing
#include <fcntl.h>
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
fd = open("myfile.txt", O_CREAT | O_WRONLY, 0644);
0644 means:
 Owner: read/write
 Group: read
 Others: read
AIM: c program to read from a file and write on standard output

#include <unistd.h>
#include <fcntl.h>
int main() {
int n, fd;
char buf[30];
fd = open("fork.c", O_RDONLY);
n = read(fd, buf, 10);
write(1, buf, 10);
return 0;
}
Compile:
Output:

11
AIM: Read from one file and write to another (create if not exists)

#include <unistd.h>
#include <fcntl.h>
int main() {
int n, fd, fd1;
char buf[50];
fd = open("fork.c", O_RDONLY);
n = read(fd, buf, 50);
fd1 = open("target", O_CREAT | O_WRONLY, 0642);
write(fd1, buf, n);
return 0;
}

Compile:
Run:
Output:

AIM: Read from standard input and append to a file

#include <unistd.h>
#include <fcntl.h>
int main()
{
int n, fd1;
char buf[50];
n = read(0, buf, 50);
fd1 = open("target", O_WRONLY | O_APPEND);
write(fd1, buf, n);
return 0;
}
Compile:
Run:
Output:

12
//Reads and displays the first 10 bytes of seeking.c.
//Skips next 10 bytes using lseek().
//Reads and displays the next 10 bytes (i.e., bytes 21–30).
 offset: Number of bytes to move
 whence:
 SEEK_SET → from beginning
 SEEK_CUR → from current position
 SEEK_END → from end

//lseek()-Reposition read/write file offset

(a) AIM: C program to demonstrate lseek()


#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
int n, f, f1;
char buff[40];
f = open("seek.txt", O_RDONLY);
read(f, buff, 10); // Reads first 10 bytes.
write(1, buff, 10); // Writes those bytes to standard output (screen).
printf("\n");
lseek(f, 5, SEEK_SET); // Moves file pointer to byte 5 from beginning.
read(f, buff, 10);
write(1, buff, 10);
printf("\n");
lseek(f, 5, SEEK_CUR); // Moves file pointer 5 bytes forward from current position.
read(f, buff, 10);
write(1, buff, 10);
printf("\n");
lseek(f, -15, SEEK_END); // Moves pointer to 15 bytes before the end of the file.
read(f, buff, 10);
write(1, buff, 10);
printf("\n");
return 0;
}
Compile:
Run:
Output:

13
AIM: C program to demonstrate Reading, writing, Seeking in Files

// read from one file and write into another file


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

int main() {
int fd[2];
char buf1[50] = "Just a sample\n";
char buf2[50];

fd[0] = open("file5.c", O_RDWR);


fd[1] = open("file6.c", O_RDWR);

write(fd[0], buf1, strlen(buf1));

printf("\nEnter the text now...");


gets(buf1);

write(fd[0], buf1, strlen(buf1));

lseek(fd[0], 0, SEEK_SET);

read(fd[0], buf2, sizeof(buf1));

printf("\n%s", buf2);

write(fd[1], buf2, strlen(buf2));


close(fd[0]);
close(fd[1]);
printf("\n");
return 0;
}
Compile:
Run:
Output:

14
EXPERIMENT 3

OBJECTIVE
Write C programs to demonstrate various process related concepts.
(a) zombie process (b)orphan process

DESCRIPTION: Zombie Process

 On UNIX operating system, a zombie process is a process that has completed the execution
but still has an entry in the process table, allowing the process that started it to read its exit
status.
 In other words, the child process has died but has not been reaped.
 When a process ends, all of the memory and resources associated with it are deallocated so
that they can be used by other processes. However, the processes entry in the process table
remains.
 The parent is sent a signal indicating that the child has died; the handler for this signal will
typically execute the system call, which reads the exit state and removes the zombie.

(a)AIM: To show existence of a zombie process


#include<stdio.h>
#include<fcntl.h>
#include<unistd.h>
#include<sys/stat.h>
#include<stdlib.h> int
main(){
int pid; pid=fork();
if(pid<0){
perror("ERROR");
exit(1);
}
else if(pid==0){
printf("In a child process\n");
printf("pid=%d \n",getpid());
printf("parent's pid=%d \n",getppid());
system("ps -l");
}

15
else {
sleep(1);
printf("In a parent process\n");
printf("pid=%d \n",getpid());
printf("parent's pid=%d \n",getppid());
printf("child's pid=%d \n",pid);
system("ps -l");
}
}
Compile:
Run:
Output:

16
DESCRIPTION: Orphan process

 An orphan process is a computer process whose parent process has finished or terminated.
 A process can become an orphan during remote invocation when the client process crashes
after making a request of the server.
 A process can also be orphaned during run time on the same machine as its parent process.

In a UNIX-like operating system, any orphaned process will be immediately adopted by the
special “init” system process.

This operation is called re-parenting and occurs automatically. Even though, technically, the
process has the “init” process as its parent, it is still called an orphan process since the process
which originally created it, no longer exists.

(b)AIM: To show existence of an orphan process

#include<stdio.h>
#include<fcntl.h>
#include<unistd.h>
#include<sys/stat.h>
#include<stdlib.h>
int main(){
int pid;
pid=fork();
if(pid<0){
perror("ERROR");
exit(1);
}
else if(pid==0){
sleep(1);
printf("In a child process\n");
printf("pid=%d \n",getpid());
printf("parent's pid=%d \n",getppid());
}
else{
printf("In a parent process\n");
printf("pid=%d \n",getpid());
printf("parent's pid=%d \n",getppid());
printf("child's pid=%d \n",pid);
}

17
Compile:
Run:
Output:

EXPERIMENT 4
OBJECTIVE
Write C programs to demonstrate various thread related concepts
(a) Thread Creation and Termination (b) Thread Creation and Termination using semaphore
( c) Multithreading

DESCRIPTION:
A thread is an independent stream of instructions that can be scheduled to run as such by the OS.
From the developers point of view a thread is a procedure that runs independently from its main
program. A program containing several procedures being able to be scheduled to run
simultaneously and/or independently by the OS is said to be a multithreaded program. Threads
exist within a process and use process resources .A thread is “lightweight” because most of the
overhead has already been accomplished through the creation of its process
 Since threads within the same process share resources
Changes made by one thread will be seen by other threads
Two pointers having the same value point to the same data
Reading and writing to the same memory location is possible and therefore require
explicit synchronization by the programmer

Pthreads
Pthreads are defined as a set of C language programming types and procedure calls, implemented
with a <pthread.h> header/include file and a thread library. Original Pthreads API was in the
ANSI/IEEE POSIX 1003.1-1995 standard. But continued to evolve and undergo revisions
Subroutines comprising the Pthreads API informally grouped into 4 major groups:
Thread management
• Work directly on thread (creation, detaching, joining etc.)

18
Mutexes
• Deal with synchronization, called a “mutex” (mutual exclusion)
• Functions include for crating, destroying, locking and unlocking mutexes
• Supplemented by mutex attribute functions that set or modify attributes associated with
mutexes
Condition variables
• Address communication between threads that share a mutex
• Based on the programmer
• Include functions to create, destroy, wait and signal based on specified variable values
• Functions to set/query condition variable attributes are also included.
Synchronization
• These routines manage read/write locks and barriers

Thread management APIs:

Thread creation pthread_create() :


o Initially main() program comprises a single, default thread. All other threads must be explictly
created by the programmer.
o pthread_create() creates a new thread and makes it executable. It can be called any no. Of
times within the program.
Syntax:
pthread_create (thread, attr, start_routine, arg)

arguments:
thread: unique identifier for the new thread returned by the subroutine
attr: attribute object, that may be set thread attributes.. you can specify a thread
atttribute obejct or NULL. For default values
start_routine: the C routine that the thread will execute once it is created
arg: a single argument that may be passed to start_routine. It must be passed by
reference as a pointer cast of ype void. NULL may be used if no argument is to be
passed.
o Maximum number of threads that can be created by a process is implementation dependent.
Thread attributes:

19
o By default, a thread is created with certain attributes. Some of the attributes can be changed by
the programmer via the thread attribute object.
Thread joining:
Syntax:
pthread_join (threadid, status)

"Joining" is one way to accomplish synchronization between threads.


o The pthread_join () subroutine blocks the calling thread until the specified thread id thread
terminates.
o The programmer is able to obtain the target thread's termination return status if it was
specified in the target thread's call to pthread_exit().
o A joining thread can match one pthread_join() call. It is a logical error to attempt multiple
joins on the same thread.

(a) AIM: Thread Creation and Termination


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

void *print_message_function( void *ptr );


main()
{
pthread_t thread1, thread2;
char *message1 = "Thread 1";
char *message2 = "Thread 2";
int iret1, iret2;

/* Create independent threads each of which will execute function */

iret1 = pthread_create( &thread1, NULL, print_message_function, (void*) message1);


iret2 = pthread_create( &thread2, NULL, print_message_function, (void*) message2);

/* Wait till threads are complete before main continues. Unless we */

20
/* wait we run the risk of executing an exit which will terminate */

pthread_join( thread1, NULL);


pthread_join( thread2, NULL);

printf("Thread 1 returns: %d\n",iret1);


printf("Thread 2 returns: %d\n",iret2);
exit(0);
}

void *print_message_function( void *ptr )


{
char *message;
message = (char *) ptr;
printf("%s \n", message);
}
Compile:
Run:
Output:

(b) AIM: Thread Creation and Termination Using semaphore


#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
void *functionC();
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
int counter = 0;
main()
{
int rc1, rc2;

21
pthread_t thread1, thread2;
/* Create independent threads each of which will execute functionC */
if( (rc1=pthread_create( &thread1, NULL, &functionC, NULL)) )
{
printf("Thread creation failed: %d\n", rc1);
}
if( (rc2=pthread_create( &thread2, NULL, &functionC, NULL)) )
{
printf("Thread creation failed: %d\n", rc2);
}
/* Wait till threads are complete before main continues. Unless we */
pthread_join( thread1, NULL);
pthread_join( thread2, NULL);
exit(0);
}
void *functionC()
{
pthread_mutex_lock( &mutex1 );
counter++;
printf("Counter value: %d\n",counter);
pthread_mutex_unlock( &mutex1 );
}
Compile:
Run:
Output:

22
AIM: To Demonstrate Multithreading
#include<pthread.h>

#include<stdio.h>
#define NUM_THREADS 3
int je,jo,evensum=0,sumn=0,oddsum=0,evenarr[50],oddarr[50];
void *Even(void *threadid)
{
int i,n;
je=0;
n=(int)threadid;
for(i=1;i<=n;i++)
{
if(i%2==0)
{
evenarr[je]=i;
evensum=evensum+i;
je++;
}}}
void *Odd(void *threadid)
{
int i,n;
jo=0;
n=(int)threadid;
for(i=0;i<=n;i++)
{
if(i%2!=0)
{
oddarr[jo]=i;
oddsum=oddsum+i;
jo++;
}}}

23
void *SumN(void *threadid)
{
int i,n;
n=(int)threadid;
for(i=1;i<=n;i++)
{
sumn=sumn+i;
}}
int main()
{
pthread_t threads[NUM_THREADS];
int i,t;
printf("enter a number\n");
scanf("%d",&t);
pthread_create(&threads[0],NULL,Even,(void *)t);
pthread_create(&threads[1],NULL,Odd,(void *)t);
pthread_create(&threads[2],NULL,SumN,(void *)t);
for(i=0;i<NUM_THREADS;i++)
{
pthread_join(threads[i],NULL);
}
printf("the sum of first N natural nos is %d\n",sumn);
printf("the sum of first N even natural nos is %d\n",evensum);
printf("the sum of first N odd natural nos is %d\n",oddsum);
printf("the first N even natural nos is --- \n");
for(i=0;i<je;i++)
printf("%d\n",evenarr[i]);
printf("the first N odd natural nos is --- \n");
for(i=0;i<jo;i++)
printf("%d\n",oddarr[i]);
pthread_exit(NULL); }

24
Compile:
Run:
Output:

EXPERIMENT 5

OBJECTIVE
Write C programs to simulate CPU scheduling algorithms:
(a) FCFS (b) SJF (c) priority (d)Round Robin

DESCRIPTION:
CPU scheduling is a process which allows one process to use the CPU while the execution of
another process is on hold(in waiting state) due to unavailability of any resource like I/O etc,
thereby making full use of CPU. The aim of CPU scheduling is to make the system efficient, fast
and fair.
Whenever the CPU becomes idle, the operating system must select one of the processes in
the ready queue to be executed. The selection process is carried out by the short-term scheduler
(or CPU scheduler). The scheduler selects from among the processes in memory that are ready to
execute, and allocates the CPU to one of them.
Dispatcher
The dispatcher is the module that gives control of the CPU to the process selected by the short-
term scheduler.
CPU Scheduling: Scheduling Criteria
There are many different criterias to check when considering the "best" scheduling algorithm,
they are:
CPU Utilization
To make out the best use of CPU and not to waste any CPU cycle, CPU would be working most of
the time(Ideally 100% of the time). Considering a real system, CPU usage should range from 40%
(lightly loaded) to 90% (heavily loaded.)

25
Throughput
It is the total number of processes completed per unit time or rather say total amount of work
done in a unit of time. This may range from 10/second to 1/hour depending on the specific
processes.
Turnaround Time
It is the amount of time taken to execute a particular process, i.e. The interval from time of
submission of the process to the time of completion of the process(Wall clock time).
Turnaround Time=Completion Time - Arrival Time
Waiting Time
The sum of the periods spent waiting in the ready queue amount of time a process has been
waiting in the ready queue to acquire get control on the CPU.
Waiting Time=Turnaround Time - Burst Time
Load Average
It is the average number of processes residing in the ready queue waiting for their turn to get
into the CPU.
Response Time
Amount of time it takes from when a request was submitted until the first response is produced.
Remember, it is the time till the first response and not the completion of process execution(final
response).
In general CPU utilization and Throughput are maximized and other factors are reduced for
proper optimization.
Response Time=First instance of CPU(for any process) – Arrival Time(of that process)

DESCRIPTION: The First Come First Serve(FCFS) Scheduling algorithms:

 The First Come First Serve (FCFS) CPU Scheduling is by far the simplest algorithm.
 As the name indicates, the process that requests the CPU first, is allocated the CPU.
 The implementation of the FCFS policy is easily managed by a FIFO queue. When a
process enters the queue (ready queue), its PCB is linked onto the tail of the queue. When
the CPU is free, it is allocated to the process at the head of the queue. The running process
is then removed from the queue.
 The average waiting time under the FCFS policy, however, is often quite long.
 The FCFS Scheduling Algorithm is non-preemptive. Once the CPU has been allocated to
a process, that process keeps the CPU until it releases the CPU, either by terminating or
by requesting I/O.
 Data structures: A simple FIFO queue is used.

26
AIM:To Implement First Come, First Serve (FCFS) Cpu Scheduling Algorithm

#include<stdio.h>
int main(){
int n,i;
int wt[20],bt[20],tat[20],Twt=0,Ttat=0;
float Avgwt=0,Avgtat=0;
system("clear");
printf("Enter the number of processes\n");
scanf("%d",&n);
printf("Enter the burst time for each process\n");
for(i=0;i<n;i++){
scanf("%d",&bt[i]);
}
wt[0]=0;
for(i=1;i<n;i++){
wt[i]=wt[i-1]+bt[i-1];
Twt+=wt[i];
}
for(i=0;i<n;i++){
tat[i]=wt[i]+bt[i];
Ttat+=tat[i];
}
Avgwt=(float)Twt/n;
Avgtat=(float)Ttat/n;
printf("P no\tB.T\tW.T\tT.A.T\n");
for(i=0;i<n;i++)
{
printf("%d\t%d\t%d\t%d\n",i+1,bt[i],wt[i],tat[i]);
}
printf(" \t \t%d\t%d\n",Twt,Ttat);
printf(" \t \t%.2f\t%.2f\t\n",Avgwt,Avgtat);
}

27
Compile:
Run:
Output:

DESCRIPTION: Shortest Job First(SJF)


Shortest Job First scheduling works on the process with the shortest burst time of a process
or duration first.
 This is the best approach to minimize waiting time.
 This is used in Batch Systems.
 It is of two types:
1. Non Pre-emptive
2. Pre-emptive
 To successfully implement it, the burst time/duration time of the processes should be
known to the processor in advance, which is practically not feasible all the time. 
 This scheduling algorithm is optimal if all the jobs/processes are available at the same time.
(either Arrival time is 0 for all, or Arrival time is same for all) 
 Data structures used: A priority queue is used

28
(a) AIM:To Implement Shortest Job First(SJF) Cpu Scheduling Algorithm

#include<stdio.h>
#include<stdlib.h>
int main(){
int n,i=0,temp=0,j=0;
system("clear");
int
wt[20],bt[20],tat[20],pno[20],Twt=0,Ttat=0;
float Avgwt=0,Avgtat=0;
system("clear");
printf("Enter the number of processes\n");
scanf("%d",&n);
printf("Enter the burst time for each process\n");
for(i=0;i<n;i++){
scanf("%d",&bt[i]);
pno[i]=i;
}
for(i=0;i<n;i++){
for(j=i+1;j<n;j++){
if(bt[j]<bt[i]){
temp=bt[j];
bt[j]=bt[i];
bt[i]=temp;
temp=0;
temp=pno[j];
pno[j]=pno[i];
pno[i]=temp;
}}
}
wt[0]=0;
for(i=1;i<n;i++){
wt[i]=wt[i-1]+bt[i-1];
Twt+=wt[i];
}
for(i=0;i<n;i++){
tat[i]=wt[i]+bt[i];
Ttat+=tat[i];
}
Avgwt=(float)Twt/n;
Avgtat=(float)Ttat/n;
printf("P no\tB.T\tW.T\tT.A.T\n");
for(i=0;i<n;i++){
printf("%d\t%d\t%d\t%d\n",pno[i],bt[i],wt[i],tat[i]);
}
printf(" \t \t%d\t%d\n",Twt,Ttat);
printf(" \t \t%.2f\t%.2f\t\n",Avgwt,Avgtat);
}
29
Compile:
Run:
Output:

30
DESCRIPTION: Round-Robin Cpu scheduling algorithm
Round robin scheduling is a preemptive version of first-come, first-served scheduling. Processes
are dispatched in a first-in-first-out sequence but each process is allowed to run for only a limited
amount of time. This time interval is known as a time-slice or quantum. If a process does not
complete or get blocked because of an I/O operation within the time slice, the time slice expires
and the process is preempted. process gets blocked because of an I/O operation), it is then
preempted. This preempted process is placed at the back of the run queue where it must wait for
the processes that were already on the list to cycle through the CPU.

(b) AIM: Simulation of Round-Robin CPU scheduling algorithm

#include<stdio.h>
#include<sys/stat.h>
int main(){
int n,i,count=0,t=0,ts, wt[20],bt[20],tat[20],Twt=0,Ttat=0,RT[15];
float Avgwt=0,Avgtat=0;
system("clear");
printf("Enter the number of processes\n");
scanf("%d",&n);
printf("Enter the time slice\n");
scanf("%d",&ts);
printf("Enter the burst time for each process\n");
for(i=1;i<=n;i++){
scanf("%d",&bt[i]);
RT[i]=bt[i];
}
while(1){
for(i=1;i<=n;i++){
if(RT[i]>0){
if(RT[i]>ts){
RT[i]-=ts;
t=t+ts;
}

31
else{
t=t+RT[i];
RT[i]=0;
tat[i]=t;
count++;
}
}
}

if(count==n){
break;
}
}
for(i=1;i<=n;i++){
wt[i]=tat[i]-bt[i];
Twt+=wt[i];
}
for(i=1;i<=n;i++){
Ttat+=tat[i];
}

Avgwt=(float)Twt/n;

Avgtat=(float)Ttat/n;
printf("P
no\tB.T\tW.T\tT.A.T\n");
for(i=1;i<=n;i++){
printf("%d\t%d\t%d\t%d\n",i,bt[i],wt[i],tat[i]);
}
printf(" \t \t%d\t%d\n",Twt,Ttat);
printf(" \t \t%.2f\t%.2f\t\n",Avgwt,Avgtat);
}

Compile:
Run:
Output:

32
EXPERIMENT 6
OBJECTIVE
Write C programs to simulate Intra & Inter-Process Communication (IPC) techniques:
(A) Pipes (B) Messages Queues (C) Shared Memory.

DESCRIPTION:

One of the mechanisms that allow related-processes to communicate is the pipe. A pipe is a one-
way mechanism that allows two related processes (i.e. one is an ancestor of the other) to send a
byte stream from one of them to the other one. The system assures us of one thing: The order in
which data is written to the pipe is the same order as that in which data is read from the pipe. The
system also assures that data won't get lost in the middle, unless one of the processes (the sender
or the receiver) exits prematurely. An echo server is usually an application which is used to test
if the connection between a client and a server is successful. It consists of a server which sends
back whatever text the client sends. The program shows communication between 2 processes
using the IPC mechanism – pipes.
System Calls Used: pipe()
This system call is used to create a read-write pipe that may later be used to communicate with a
process we'll fork off. The call takes as an argument an array of 2 integers that will be used to save
the two file descriptors used to access the pipe. The first one to read from the pipe and the second
one to write to the pipe.
Syntax:
#include <unistd.h>
int pipe (int fd[2]);

Return: 0 on success
-1 on errors

fd[0] is set up for reading and fd[1] is set up for writing. The first element in the array (element 0) is
set up and opened for reading while the second element (element 1) is setup and opened for writing.

33
(A) AIM : To implement two-process communication through using unnamed pipes.

//.a unnamed pipes


#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h> int
main()
{
int pid,a[2],b[2];
char str[30],buff1[30],buff2[30];
pipe(a);
pipe(b); pid=fork();
if(pid==0)
{
strcpy(str,"Welcome to OS lab");
write(a[1],str,strlen(str)+1);
sleep(2);
read(b[0],buff1,sizeof(buff1));
printf("response from parent is %s\n",buff1);
}
else
{
read(a[0],buff2,sizeof(buff2));
printf("request from child is %s\n",buff2);
strcpy(buff2,"parent says hello");
write(b[1],buff2,sizeof(buff2));
exit(1);
}
}
Compile:
Run:
Output:

34
AIM: Program to demonstrate IPC using Unnamed Pipes

DESCRIPTION: One of the mechanisms that allow processes to communicate is the named
pipe (fifo). A FIFO special file (a named pipe) is similar to a pipe, except that it is accessed as
part of the filesystem. It can be opened by multiple processes for reading or writing. When
processes are exchanging data via the FIFO, the kernel passes all data internally
without writing it to the filesystem. fifo is a two-way mechanism that allows two unrelated
processes to send/ receive a byte stream between them. The program shows communication
between 2 processes using the IPC mechanism – fifo.
System Calls Used: mkfifo()
mkfifo() makes a FIFO special file with name pathname. Mode specifies the FIFO's permissions.
Syntax:
#include <sys/types.h> #include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
Return: 0 on success
-1 on errors

(a)AIM: To implement inter-process communication through Named pipes (fifo).

//5.b Named Pipes( fifo)


//Program 1 Writes First
#include<stdio.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<unistd.h>
#include<fcntl.h>
#include<string.h>
int main(){
int fd;
char str1[100],str2[100];
fd= mkfifo("fifo1",0644);
printf("named pipe created\n");
while(1){
fd=open("fifo1",O_WRONLY);
fgets(str1,100,stdin);
write(fd,str1,strlen(str1)+1);
close(fd);
fd=open("fifo1",O_RDONLY);
read(fd,str2,sizeof(str2));
printf("user2:%s\n",str2);
close(fd);
}}

35
//Program 2 Reads First
#include<stdio.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<unistd.h>
#include<fcntl.h>
#include<string.h>
int main()
{
int fd;
char str1[100],str2[100];
while(1)
{
fd=open("fifo1",O_RDONLY);
read(fd,str1,sizeof(str1));
printf("user1:%s\n",str1);
close(fd);
fd=open("fifo1",O_WRONLY);
fgets(str2,100,stdin);
write(fd,str2,strlen(str2)+1);
close(fd);
}

Compile:
Run:
Output:

36
(B) AIM: Program to demonstrate IPC using message queues

Description: In message queue, a mail box is created. The OS should read and write program. A
message queue is created and owned by one process. A message queue is created by a msgget call
with the following syntax
msgget( key, flag )
The OS maintains an array of message queues and their keys. The first msgget call results in creation
of new message queue.

The position of the message queue in the system array (called the message queue id ) is returned by
the msgget call. This id’s are used in a send or receive call.
The send and receive calls have the following syntax:
msgsnd( msgqid, msg, count, flag );
msgrcv( msgqid, msg-struct-ptr, maxcount, type, flag );

The count and flag parameters of msgsnd specify number of bytes in a message and the actions it
should take if sufficient space is not available in message queue (e.g. Block the sender).
In msgrcv call, msg-struct-ptr is the address of the structure to receive the message, maxcount is
maximum length of message, type indicates the type of message to be received. When a message
is sent to a message queue on which many processes are waiting, the operating system wakes all
processes. When type parameter in msgrcv is positive, the operating system returns the first
message with a matching type and if it is negative, the operating system returns the lowered
number message with the type value less than the absolute value specified in the call.
An echo server is usually an application which is used to test if the connection between a client
and a server is successful. It consists of a server which sends back whatever text the client sends.
The program shows communication between 2 processes using the IPC mechanism: message
queues

37
// msgQueue
#include<stdio.h>
#include<string.h>
#include<sys/msg.h>
#include<sys/ipc.h>
#include<unistd.h>
int main()
{
int pid,msqid;
char buff[20],buff1[20],a[20];
msqid=msgget((key_t)151,IPC_CREAT|0600);
pid=fork();
if(pid==0)
{ strcpy(a,"160424733161");
msgsnd(msqid,a,12,0);
sleep(2);
msgrcv(msqid,buff1,18,0,0);
printf(" echoed message is %s\n",buff1);
}
else
{
sleep(1);
msgrcv(msqid,buff,12,0,0);
printf("message received is %s\n",buff);
strcat(buff," pass");
msgsnd(msqid,buff,18,0);
}}
Compile:
Run:
Output:

38
( C) DESCRIPTION: IPC using shared memory

Shared Memory is an efficient means of passing data between programs. One program will
create a memory portion which other processes (if permitted) can access. A process creates a
shared memory segment using shmget. Once created, a shared segment can be attached to a
process addressspace using shmat(). It can be detached using shmdt(). Once attached, the process
can read or write to the segment, as allowed by the permission requested in the attach operation.
A shared memory segment is described by a control structure with a unique ID that point to an
area of physical memory. The identifier of the segment is called the shmid. The structure
definition for the shared memory segment control structures and prototype can be found in
<sys/shm.h>
shmget () - allocates a System V shared memory segment
System Calls used: shmget (),shmat(), shmdt()

Syntax:
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);.

Return: On success, a valid segment identifier, shmid, -1 on error.

The argument key is the value of the IPC key to use. The size argument specifies the minimum
size of the shared memory region required. The flag option must contain the permission bits if
shared memory is being created. Additional flags that may be used include IPC_CREAT and
IPC_EXCL, when shared memory is being created.

#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);
int shmdt(const void *shmaddr);

Return: On success shmat() returns the address of the attached shared memory segment; on
error (void *) -1 is returned.
On success shmdt() returns 0; on error -1 is returned, and errno is set to indicate the cause of the
error.

39
( C )AIM : Write a program to illustrate communication between processes using shared memory

// sharedmemory
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/ipc.h>
#include<string.h>
#include<sys/shm.h>
int main(){
int pid,shmid;
char *p;
shmid=shmget((key_t)224,20,IPC_CREAT|0600);
p=(char*)shmat(shmid,0,0);
pid=fork();
if(pid==0){
strcpy(p,"data in shared memory\n");
}
else if(pid>0)
{
sleep(1);
printf("%s\n",p);
}
else{
perror("error");
}
}

Compile:
Run:
Output:

40
EXPERIMENT 7
OBJECTIVE
Write C programs to simulate solutions to Classical Process Synchronization Problems:
(A) Dining Philosophers (B) Producer-Consumer (C) Readers-Writers

DESCRIPTION: Dining Philosopher’s problem


The dining-philosophers problem is considered a classic synchronization problem because it is an
example of a large class of concurrency-control problems. It is a simple representation of the need
to allocate several resources among several processes in a deadlock-free and starvation-free
manner. Consider five philosophers who spend their lives thinking and eating. The philosophers
share a circular table surrounded by five chairs, each belonging to one philosopher. In the center
of the table is a bowl of rice, and the table is laid with five single chopsticks. When a philosopher
thinks, she does not interact with her colleagues. From time to time, a philosopher gets hungry and
tries to pick up the two chopsticks that are closest to her (the chopsticks that are between her and
her left and right neighbors). A philosopher may pick up only one chopstick at a time. Obviously,
she cam1ot pick up a chopstick that is already in the hand of a neighbor. When a hungry
philosopher has both her chopsticks at the same time, she eats without releasing her chopsticks.
When she is finished eating, she puts down both of her chopsticks and starts thinking again. The
dining-philosophers problem may lead to a deadlock situation and hence some rules have to be
framed to avoid the occurrence of deadlock.
 One simple solution is to represent each chopstick by a semaphore.
A semaphore S is an integer variable that can be accessed only through two standard operations :
wait()andsignal().
The wait() operation reduces the value of semaphore by 1 and the signal() operation increases its
value by 1.
There are two types of semaphores 1)Binary Semaphore 2)counting semaphore

The structure of philosopher(i) is shown:


do{
wait(chopstick[i]);
wait(chopstick(i+1)%5);
……..
//eat
……..
signal(chopstick[i]);
signal(chopstick[i+1]%5);
……….
//think
……….
}while(TRUE);

41
(7.A)AIM: To implement Dining Philosopher’s Problem using semaphore

// dining philosophers
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
#include<semaphore.h>
# define N 5
# define THINKING 0
# define HUNGRY 1
# define EATING 2
# define LEFT (phnum+N-1)%N
# define RIGHT (phnum+1)%N
int phnum;
int state[N];
int phil[N]={0,1,2,3,4};
sem_t mutex;
sem_t s[N];
void test(int phnum){
if(state[phnum]==HUNGRY && state[LEFT]!=EATING &&
state[RIGHT]!=EATING){ state[phnum]=EATING;
sleep(2);
printf("phil %d takes fork %d and %d\n",phnum+1,LEFT+1,phnum+1);
printf("phil %d is eating\n",phnum+1);
sem_post(&s[phnum]);
}
}
void takefork(int phnum){
sem_wait(&mutex);
state[phnum]=HUNGRY;
printf("phil %d is hungry\n",phnum+1);
test(phnum);
sem_post(&mutex);
sem_wait(&s[phnum]);
sleep(1); }

42
void putfork(int phnum)
{
sem_wait(&mutex);
state[phnum]=THINKING;
printf("phil %d putsdown fork %d and %d\n",phnum+1,LEFT+1,phnum+1);
printf("phil %d is in thinking state\n",phnum+1);
test(LEFT);
test(RIGHT);
sem_post(&mutex);
}
void * philosopher(void * num)
{
while(1)
{
int * i=num;
sleep(1);
takefork(* i);
sleep(1);
putfork(* i);
}
}
int main(){
int i;
pthread_t tid[N];
sem_init(&mutex,0,1);
for(i=0;i<N;i++)
sem_init(&s[i],0,0);
for(i=0;i<N;i++){
pthread_create(&tid[i],NULL,philosopher,&phil[i]);
printf("phil %d is thinking\n",phil[i]+1);
}
for(i=0;i<N;i++){
pthread_join(tid[i],NULL);
}
}

43
Compile:
Run:
Output:

44
OBJECTIVE: C Program to implement Producer Consumer problem

DESCRIPTION:
Producer consumer problem is also known as bounded buffer problem. In this problem we have
two processes, producer and consumer, who share a fixed size buffer. Producer work is to produce
data or items and put in buffer. Consumer work is to remove data from buffer and consume it. We
have to make sure that producer do not produce data when buffer is full and consumer do not
remove data when buffer is empty.
The producer should go to sleep when buffer is full. Next time when consumer removes data it
notifies the producer and producer starts producing data again. The consumer should go to sleep
when buffer is empty. Next time when producer add data it notifies the consumer and consumer
starts consuming data. This solution can be achieved using semaphores.
To solve this problem, we need two counting semaphores – Full and Empty. “Full” keeps track of
number of items in the buffer at any given time and “Empty” keeps track of number of unoccupied
slots.
Initialization of semaphores– mutex=1, Full = 0 // Initially, all slots are empty. Thus full slots
are 0 Empty = n // All slots are empty initially

Producer – When producer produces an item then the value of “empty” is reduced by 1 because
one slot will be filled now. The value of mutex is also reduced to prevent consumer to access the
buffer. Now, the producer has placed the item and thus the value of “full” is increased by 1. The
value of mutex is also increased by 1 beacuse the task of producer has been completed and
consumer can access the buffer.
Consumer – As the consumer is removing an item from buffer, therefore the value of “full” is
reduced by 1 and the value is mutex is also reduced so that the producer cannot access the buffer
at this moment. Now, the consumer has consumed the item, thus increasing the value of “empty”
by 1. The value of mutex is also increased so that producer can access the buffer now.

45
(7.B)AIM: To implement Producer &Consumer problem using semaphore

#include<stdio.h>
#include<stdlib.h>
int mutex=1,full=0,empty=3,x=0;
int main()
{
int n;
void producer();
void consumer();
int wait(int);
int signal(int);
printf("\n1.Producer\n2.Consumer\n3.Exit");
while(1)
{
printf("\nEnter your choice:");
scanf("%d",&n);
switch(n)
{
case 1: if((mutex==1)&&(empty!=0))
producer();
else
printf("Buffer is full!!");
break;
case 2: if((mutex==1)&&(full!=0))
consumer();
else
printf("Buffer is empty!!");
break;
case 3:
exit(0);
break;
}
}
return 0;
}

int wait(int s)
{
return (--s);
}
int signal(int s)

46
{
return(++s);
}

void producer()
{
mutex=wait(mutex);
full=signal(full);
empty=wait(empty);
x++;
printf("\nProducer produces the item %d",x);
mutex=signal(mutex);
}

void consumer()
{
mutex=wait(mutex);
full=wait(full);
empty=signal(empty);
printf("\nConsumer consumes item %d",x);
x--;
mutex=signal(mutex);
}
Compile:
Run:
Output:

47
DESCRIPTION: Readers-Writer problem
Readers writer problem is another example of a classic synchronization problem.

There is a shared resource which should be accessed by multiple processes. There are two types
of processes in this context. They are reader and writer. Any number of readers can read from the
shared resource simultaneously, but only one writer can write to the shared resource. When
a writer is writing data to the resource, no other process can access the resource. A writer cannot
write to the resource if there are non zero number of readers accessing the resource at that time.
Solution when Reader has the Priority over Writer
Here priority means, no reader should wait if the share is currently opened for reading.
Three variables are used: mutex, wrt, readcnt to implement solution
1. semaphore mutex, wrt; // semaphore mutex is used to ensure mutual exclusion
when readcnt is updated i.e. when any reader enters or exit from the critical section and
semaphore wrt is used by both readers and writers
2. int readcnt; // readcnt tells the number of processes performing read in the critical
section, initially 0
Functions for sempahore :
– wait() : decrements the semaphore value.
– signal() : increments the semaphore value.
Writer process:
1. Writer requests the entry to critical section.
2. If allowed i.e. wait() gives a true value, it enters and performs the write. If not allowed, it
keeps on waiting.
3. It exits the critical section.
The code for the writer process:
While(True)
{
// writer requests for critical section
wait(w);
// performs the write
// leaves the critical section
signal(w);
}

48
Reader process:
1. Reader requests the entry to critical section.
2. If allowed:
it increments the count of number of readers inside the critical section. If this reader
is the first reader entering, it locks the wrtsemaphore to restrict the entry of writers
if any reader is inside.
It then, signals mutex as any other reader is allowed to enter while others are already
reading.
After performing reading, it exits the critical section. When exiting, it checks if no
more reader is inside, it signals the semaphore “wrt” as now, writer can enter the
critical section.
3. If not allowed, it keeps on waiting.
And, the code for the reader process
while(TRUE)
{
//acquire lock
wait(m);
read_count++;
if(read_count == 1)
wait(w);

//release lock
signal(m);
/* perform the reading operation */
// acquire lock
wait(m);
read_count--;
if(read_count == 0)
signal(w);
// release lock
signal(m);
}

49
(7.C)AIM: To implement Readers and Writer problem using semaphore

#include<stdio.h>
#include<pthread.h>
#include<semaphore.h>
sem_t mutex,writeblock;
int data = 0,rcount = 0;
void *reader(void *arg)
{
int f;
f = ((int)arg);
sem_wait(&mutex);
rcount = rcount + 1;
if(rcount==1)
sem_wait(&writeblock);
sem_post(&mutex);
printf("Data read by the reader%d is %d\n",f,data);
sleep(1);
sem_wait(&mutex);
rcount = rcount - 1;
if(rcount==0)
sem_post(&writeblock);
sem_post(&mutex);
}

void *writer(void *arg)


{
int f;
f = ((int) arg);
sem_wait(&writeblock);
data++;
printf("Data writen by the writer%d is %d\n",f,data);
sleep(1);
sem_post(&writeblock);
}

main()
{
int i,b;
pthread_t rtid[5],wtid[5];
sem_init(&mutex,0,1);

50
sem_init(&writeblock,0,1);
for(i=0;i<=2;i++)
{
pthread_create(&wtid[i],NULL,writer,(void *)i);
pthread_create(&rtid[i],NULL,reader,(void *)i);
}
for(i=0;i<=2;i++)
{
pthread_join(wtid[i],NULL);
pthread_join(rtid[i],NULL);
}
}

Compile:
Run:
Output:

EXPERIMENT 8
OBJECTIVE
Write C programs to simulate Page Replacement Algorithms:
(A)FIFO (B) LRU

DESCRIPTION
Page replacement is basic to demand paging. It completes the separation between logical memory
and physical memory. With this mechanism, an enormous virtual memory can be provided for
programmers on a smaller physical memory. There are many different page-replacement
algorithms. Every operating system probably has its own replacement scheme. A FIFO
replacement algorithm associates with each page the time when that page was brought into
memory. When a page must be replaced, the oldest page is chosen. We replace the page at the head
of the queue. When a page is brought into memory, we insert it at the tail of the queue. If the
recent past is used as an approximation of the near future, then the page that has not been used for
the longest period of time can be replaced. This approach is the Least Recently Used (LRU)
algorithm. LRU replacement associates with each page the time of that page's last use. When a
page must be replaced, LRU chooses the page that has not been used for the longest period of time.

51
Optimal page replacement algorithm has the lowest page-fault rate of all algorithms and will never
suffer from Belady's anomaly. The basic idea is to replace the page that will not be used for the
longest period of time. Use of this page-replacement algorithm guarantees the lowest possible page
fault rate for a fixed number of frames. Unfortunately, the optimal page-replacement algorithm is
difficult to implement, because it requires future knowledge of the reference string.

(8.A)AIM: To implement FIFO page replacement algorithms


//8.a fifo page replacement
#include<stdio.h>
#include<stdlib.h>
int main(){
int i,j,n,rs[50],f[10],nf,k=0,avail,pf=0;
float hr,mr;
system("clear");
printf("Enter number of pages\n");
scanf("%d",&n);
printf("Enter the reference string\n");
for(i=1;i<=n;i++){
scanf("%d",&rs[i]);
}
printf("Enter frame size\n");
scanf("%d",&nf);
for(i=0;i<nf;i++)
f[i]=-1;
printf("page frames\n");
for(i=1;i<=n;i++){
avail=0;
for(j=0;j<nf;j++){
if(f[j]==rs[i])
avail=1;
}
if(avail==0){
f[k]=rs[i];
k=(k+1)%nf; pf++;
for(j=0;j<nf;j++)
printf("%d\t",f[j]);
printf("pf no is %d",pf);
}
printf("\n");
}
printf("Total pf is %d\n",pf);
mr=(float)pf/n;
hr=(float)(n-pf)/n;
printf("hr,mr %.2f %.2f\n",hr,mr); }

52
Compile:
Run:
Output:

53
(8.B) AIM: To implement LRU page replacement algorithms

//8.b LRU page replacement


#include<stdio.h>
#include<stdlib.h>
int main(){
int
i,j,n,rs[50],f[10],nf,k,min,count[10],flag[20],pf=0,next=1;
float hr,mr;
system("clear");
printf("Enter number of pages\n");
scanf("%d",&n);
printf("Enter the reference string\n");
for(i=0;i<n;i++){
scanf("%d",&rs[i]);
flag[i]=0;
}
printf("Enter frame size\n");
scanf("%d",&nf);
for(i=0;i<nf;i++){
count[i]=0;
f[i]=-1;
}
printf("page frame\n");
for(i=0;i<n;i++){
for(j=0;j<nf;j++){
if(f[j]==rs[i]){
flag[i]=1;
count[j]=next;
next++;
}
}
if(flag[i]==0){
if(i<nf){
f[i]=rs[i];
count[i]=next;
next++;
}
pf++;
}
for(j=0;j<nf;j++)
printf("%d\t",f[j]);
if(flag[i]==0)
printf("pf no is %d",pf);
printf(“\n”);
}

54
printf("Total pf is %d\n",pf);
mr=(float)pf/n;
hr=(float)(n-pf)/n;
printf("hr,mr %.2f %.2f\n",hr,mr);
}

Compile:
Run:
Output:

55
EXPERIMENT 9

OBJECTIVE

Write a C program to simulate Bankers algorithm for the purpose of deadlock avoidance.
DESCRIPTION:
Banker's algorithm is a deadlock avoidance algorithm. It is named so because this algorithm is
used in banking systems to determine whether a loan can be granted or not.
Consider there are n account holders in a bank and the sum of the money in all of their accounts
is S. Every time a loan has to be granted by the bank, it subtracts the loan amount from the total
money the bank has. Then it checks if that difference is greater than S. It is done because, only
then, the bank would have enough money even if all the n account holders draw all their money
at once.
Banker's algorithm works in a similar way in computers.
Whenever a new process is created, it must specify the maximum instances of each
resource type that it needs, exactly.
Let us assume that there are n processes and m resource types. Some data structures
that are used to implement the banker's algorithm are:
1. Available
It is an array of length m. It represents the number of available resources of each type.
If Available[j] = k, then there are k instances available, of resource type R(j).
2. Max
It is an n x m matrix which represents the maximum number of instances of each
resource that a process can request. If Max[i][j] = k, then the process P(i) can request
at most k instances of resource type R(j).
3. Allocation
It is an n x m matrix which represents the number of resources of each type currently
allocated to each process. If Allocation[i][j] = k, then process P(i) is currently
allocated k instances of resource type R(j).
4. Need
It is an n x m matrix which indicates the remaining resource needs of each process.
If Need[i][j] = k, then process P(i) may need k more instances of resource type R(j) to
complete its task.
Need[i][j] = Max[i][j] - Allocation [i][j]

56
// bankers Algorithm
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int main(){
int
max[10][10],need[10][10],alloc[10][10],avail[10],fin[10],safe[10];
int pr_cnt,res_cnt,i,j,process,count=0;
system("clear");
printf(" Enter the system state information\n");
printf("Enter the number of processes\n");
scanf("%d",&pr_cnt);
for(i=0;i<pr_cnt;i++){
fin[i]=0;
}
printf("Enter the number of resources\n");
scanf("%d",&res_cnt);
printf("Enter the max matrix for all processes:\n");
for(i=0;i<pr_cnt;i++)
{
for(j=0;j<res_cnt;j++)
{
printf("Enter max info for process[%d][%d]\n",i,j);
scanf("%d",&max[i][j]);

}
}

for(i=0;i<pr_cnt;i++){
for(j=0;j<res_cnt;j++){
printf("Enter allocation info for process[%d][%d]\n",i,j);
scanf("%d",&alloc[i][j]);
}
}
printf("Enter the available resources in the system:\n");
for(i=0;i<res_cnt;i++){
printf("available[%d]=\n",i);
scanf("%d",&avail[i]);
}
for(i=0;i<pr_cnt;i++){
for(j=0;j<res_cnt;j++){
need[i][j]=max[i][j]-alloc[i][j];

} }

57
do{
printf("Available resources are:\n");
for(j=0;j<res_cnt;j++)
printf("%d\t",avail[j]);
printf("\n max matrix:\t allocation matrix:\n");
for(i=0;i<pr_cnt;i++){
for(j=0;j<res_cnt;j++){
printf("%d\t",max[i][j]);
}
printf("\t");
for(j=0;j<res_cnt;j++){
printf("%d\t",alloc[i][j]);
}
}
printf("\n");
}
process=-1;

for(i=0;i<pr_cnt;i++){
if(fin[i]==0){
process=i;
for(j=0;j<res_cnt;j++){
if(avail[j]<need[i][j]){
process=-1;
break;
}
}
}
if(process!=-1)
break;
}
if(process!=-1){
safe[count]=process+1;
count++;
for(j=0;j<res_cnt;j++){
avail[j]+=alloc[process][j];
alloc[process][j]=0;
max[process][j]=0;
fin[process]=1;
}
}
}

58
while(count!=pr_cnt && process!=-1);
if(count==pr_cnt)
{
printf("the system is in a safe state\n");
printf("Safe sequence:<");

for(i=0;i<pr_cnt;i++)
printf("%d",safe[i]);
printf(">\n");
}
else{
printf("the system is in unsafe state!!\n");
}
}

Compile:
Run:
Output:

59
60
EXPERIMENT 10

OBJECTIVE
To Write a C program to simulate disk scheduling algorithms
(A)FCFS (B)SSTF

(A)DESCRIPTION
One of the responsibilities of the operating system is to use the hardware efficiently. For the disk
drives, meeting this responsibility entails having fast access time and large disk bandwidth. Both
the access time and the bandwidth can be improved by managing the order in which disk I/O
requests are serviced which is called as disk scheduling. The simplest form of disk scheduling is,
of course, the first-come, first-served (FCFS) algorithm. FCFS (First-Come, First-Served) Disk
Scheduling Algorithm is a simple and easy-to-implement algorithm used in operating systems to
manage input/output (I/O) requests from processes to access disk blocks. In this algorithm, the
operating system processes the I/O requests in the order in which they arrive in the queue,
without any reordering or prioritization.

When a process generates an I/O request, it is added to the end of the queue, and the operating
system services the requests in the same order. The requests are serviced one by one until the
entire queue is empty. This algorithm has the advantage of being fair, predictable, and requiring
low overhead. However, it also has limitations, such as long waiting times for requests that arrive
later and potential starvation of requests that are stuck behind long-running requests.

(B) DESCRIPTION: Shortest Seek Time First (SSTF) is a disk scheduling algorithm that
prioritizes processing I/O requests that are closest to the current position of the disk head. The
algorithm selects the I/O request with the shortest seek time to the next request, in order to
reduce disk head movement and improve disk access times.
When an I/O request is generated, the SSTF algorithm selects the request that is closest to the
current position of the disk head. The algorithm processes the request with the shortest seek time
first and then selects the next closest request. This process continues until all requests are
processed.
SSTF is a more efficient algorithm than FCFS, as it prioritizes processing requests with the
shortest seek time. This reduces the amount of time the disk head spends moving across the disk,
resulting in faster access times and improved system performance. SSTF also provides better
response times for time-critical requests and can be useful in real-time systems.

61
(10.A)AIM: C program to simulate FCFS Disk scheduling Algorithm
#include<stdio.h>
#include<stdlib.h>
int main(){
int req[20],n,hdpos,tseek=0,i;
float avgmv;
printf("Enter the number of requests\n");
scanf("%d",&n);
printf("Enter the disk read requests\n");
for(i=0;i<n;i++){
//temp[i]=req[i];
scanf("%d",&req[i]);
}
printf("Enter head position\n");
scanf("%d",&hdpos);
printf("FCFS sequence is\n");
for(i=0;i<n;i++){
printf("%d->",req[i]);
tseek=tseek+abs(req[i]-hdpos);
hdpos=req[i];
}
avgmv=(float)tseek/n;
printf("\nTST is %d\n",tseek);
printf("Avgmv is %.2f\n",avgmv);
}

Compile:
Run:
Output:

62
(10.B)AIM: C program to simulate SSTF Disk scheduling Algorithm

#include<stdlib.h>
#include<limits.h>
int main(){
int
req[20],n,hdpos,tseek=0,i,temp[20],min,dist,index,cpos,cnt=0;
float avgmv;
printf("Enter the number of requests\n");
scanf("%d",&n);
printf("Enter the disk read requests\n");
for(i=0;i<n;i++){
temp[i]=req[i];
scanf("%d",&req[i]);
}
printf("Enter head position\n");
scanf("%d",&hdpos);
printf("SSTF sequence is\n");
cpos=hdpos;
while(cnt<n){
min=INT_MAX;
for(i=0;i<n;i++){
if(temp[i]!=-1){
dist=abs(req[i]-cpos);
if(min>dist){
min=dist;
index=i; }
}
}
tseek+=min;
temp[index]=-1;
cnt++;
cpos=req[index];
printf("%d->",req[index]);
if(cnt==n)
break;
}
avgmv=(float)tseek/n;
printf("\nTST is %d\n",tseek);
printf("Avgmv is %.2f\n",avgmv);
}

63
Compile:
Run:
Output:

64

You might also like