OS Lab Manual Updated 2023
OS Lab Manual Updated 2023
Name
Roll No
Branch/Section
Year
Semester
2
INDEX
OBJECTIVE:
This lab complements the operating systems course. Students will gain practical experience with
designing and implementing concepts of operating systems such as system calls, CPU scheduling,
process management, memory management, file systems and deadlock handling using C language
in Linux environment.
OUTCOMES:
Upon the completion of Operating Systems practical course, the student will be able to:
1. Understand and implement basic services and functionalities of the operating system
using system calls.
2. Use modern operating system calls and synchronization libraries in software/ hardware
interfaces.
3. Understand the benefits of thread over process and implement synchronized programs
using multithreading concepts.
4. Analyze and simulate CPU Scheduling Algorithms like FCFS, Round Robin, SJF, and
Priority.
5. simulate Intra & Inter-Process Communication (IPC) techniques: Pipes, Messages
Queues, Shared Memory.
6. Implement page replacement schemes.
multiprogramming system.
3
INTRODUCTION TO OPERATING SYSTEM
A program that act as an intermediary between a user of a computer and the computer
hardware.
An operating system can be define as a software that control the hardware resources of the
computer and provide an environment under which program can run. Generally, we call
this software as the KERNEL.
OPERATING SYSTEM GOALS
Execute user programs and make solving user problem easier.
Make the computer system convenient to use.
Operating system is a software program that enables the computer hardware to
communicate & operate with the computer software.
Without operating system a computer would be useless.
4
INTRODUCTION TO LINUX OPERTATING SYSTEM
Linux is one of popular version of UNIX operating System. It is open source as its source code is
freely available. It is free to use. Linux was designed considering UNIX compatibility. Its
functionality list is quite similar to that of UNIX.
Components of Linux System
Linux Operating System has primarily three components
Kernel − Kernel is the core part of Linux. It is responsible for all major activities of this
operating system. It consists of various modules and it interacts directly with the underlying
hardware. Kernel provides the required abstraction to hide low level hardware details to
system or application programs.
System Library − System libraries are special functions or programs using which
application programs or system utilities accesses Kernel's features. These libraries
implement most of the functionalities of the operating system and do not requires kernel
module's code access rights.
System Utility − System Utility programs are responsible to do specialized, individual
level tasks.
Architecture
The following illustration shows the architecture of a Linux system −
5
TELNET
The telnet command is used to communicate with another host using the telnet protocol. Where
hostname is the host you want to connect to & port, indicates a port number. If a number is not
specified, the default telnet is used.
Example:
Operating system Server Internet Protocol
Unix Telnet 192.168.0.2
Linux Telnet 192.168.0.6
The Linux file system is the structure in which all the information on your computer is stored.
Files are organized within a hierarchy of directories. Each directory can contain files, as well as
other directories.
If you were to map out the files and directories in Linux, it would look like an upside-down tree.
At the top is the root directory, which is represented by a single slash ( / ). Below that is a set of
common directories in the Linux system, such as bin, dev, home, lib , and tmp , to name a few.
Each of those directories, as well as directories added to the root, can contain subdirectories.
Some of the Linux directories that may interest you include the following:
.• /bin - Contains common Linux user commands, such as ls, sort , date , and chmod .
• /boot - Has the bootable Linux kernel and boot loader configuration files (GRUB).
• /dev - Contains files representing access points to devices on your systems. These include
terminal devices ( tty* ), floppy disks ( fd* ), hard disks ( hd* or sc* ),RAM ( ram* ), and CD-
ROM ( cd* ).
6
• /etc - Contains administrative configuration files.
• /home - Contains directories assigned to each user with a login account.
• /media - Provides a location for mounting devices, such as remote file systems and removable
media (with directory names of cdrom , floppy , and so on). In Fedora and RHEL, many removable
media are mounted automatically in this directory when the media is inserted (CD or DVD) or
connected (USB pen drives or cameras ).
• /proc - Provides a mechanism for the kernel to send information to processes.
• /root - Represents the root user's home directory.
• /sbin - Contains administrative commands and daemon processes.
• /tmp - Contains temporary files used by applications.
• /usr - Contains user documentation, games , graphical files (X11), libraries (lib), and a variety
of other user and administrative commands and files.
• /var - Contains directories of data used by various applications. In particular, this is where you
would place files that you share as an FTP server ( /var/ftp ) or a Web server ( /var/www ). It also
contains all system log files ( /var/log ). In time, FTP, HTTP, and similar services will move to the
/srv directory to adhere to the Linux Standards Base ( www.freestandards.org/spec ).
7
The Vi editor is a visual editor used to create and edit text, files, documents and
programs. It displays the content of files on the screen and allows a user to add, delete or
change part of text . There are three modes available in the Vi editor , they are
1. Command mode
2.Input (or) insert mode.
Starting Vi :
The Vi editor is invoked by giving the following commands in LINUX prompt.
Syntax : $vi <filename> (or) $vi
This command would open a display screen with 25 lines and with tilt (~) symbol at the
start of each line. The first syntax would save the file in the filename mentioned and for the
next the filename must be mentioned at the end.
Options :
1.vi +n <filename> - this would point at the nth line (cursor pos).
2.vi –n <filename> - This command is to make the file to read only to change from one mode to
another press escape key.
To move editor from command node to edit mode, you have to press the <ESC> key.
This command is used to insert the text before the current cursor position.
Syntax : <ESC>
SAVING AND QUITING FROM vi :-
1. <ESC> w Command :
To save the given text present in the file.
Syntax : <ESC> : w
2. <ESC> q! Command :
To quit the given text without saving.
Syntax : <ESC> :q!
3. <ESC> wq Command :
This command quits the vi editor after saving the text in the mentioned file.
Syntax : <ESC> :wq
5.<ESC> q Command :
This command would quit the window but it would ask for again to save the file.
Syntax : <ESC> : q
8
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.
9
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.
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.
10
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>
11
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>
12
EXPERIMENT 1
OBJECTIVE
Write a C programs to implement UNIX system calls
(a) fork() (b)sleep()&wait() (c)execv() (c)execlp()
fork (): 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.
calls#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
main()
{
int pid;
printf("\n Demonstration of fork system call \n");
pid=fork();
if(pid<0)
{
printf("\n not possible \n");
exit(0);
}
else
if(pid==0)
{
13
sleep(5);
printf("child processor ID is %d \n",getpid());
printf("parent processor ID is %d \n",getppid());
}
else
{
wait();
printf("parent id is %d",getpid());
printf("\nparent of parent processor ID is %d\n",getppid());
}
}
Compile: cc fork.c
Run: ./a.out
Output: Demonstration of fork system call
child processor ID is 3597
parent processor ID is 3596
parent id is 3596
parent of parent processor ID is 3201
14
(b) AIM : To demonstrate usage of wait(),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”);
}
Else if(ret_value==0)
{
//child process
printf(“\n child process\n”);
printf(“the process id is %d\n”,getpid());
sleep(20);
}
else
{
//parent process
wait()
printf(“parent process\n”);
printf(“the process id is %d\n”,getpid());
sleep(30);
}
return 0;
}
15
Compile: cc Wait_Sleep.c
Run: ./a.out
Output: The process id is 4163
child process
the process id is 4164
parent process
the process id is 4163
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.
16
Compile: cc execv.c
Run: ./a.out
Output:
Total 3
-rwxr-xr-x 1be322 group 4716 feb 26 11:30 a.out
-rw-r-r-x 1be322 group 688 feb 26 11:30 fork.c
-rw-r-r-x 1be322 group 925 feb 28 11:30 wait_sleep.c
#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: cc execlp.c
Run: ./a.out
Output: fork.c
Wait_Sleep.c
execv.c
17
EXPERIMENT 2
OBJECTIVE
Write a C programs to implement file management
DESCRIPTION:
A system call is just what its name implies, i.e, a result for the operating system to do
something on behalf of users program. The system calls are functions used in Kernel
itself.
#include<stdio.h>
#include<sys/stat.h>
#include<time.h>
#include<grp.h>
#include<pwd.h>
main(int argc,char *argv[])
{
struct stat thebuf;
char *path;
int i;
for(i=1;i<argc;i++)
{
path=argv[i];
18
if(!stat(path,&thebuf))
{
printf("\n file mode of %s %d of which is ",argv[1],thebuf.st_mode);
switch(thebuf.st_mode&S_IFMT)
{
case S_IFDIR:
printf("\n A directory file");
break;
case S_IFCHR:
printf("\n A character special file");
break;
case S_IFREG:
printf(" \n an ordinary file");
break;
case S_IFBLK:
printf("\n a block special file");
break;
case S_IFIFO:
printf("\n a fifo file");
break;
case S_IFSOCK:
printf("\n a socket");
break;
}
}
else
printf("\n cant get state on %s ",path);
}}
Compile: cc Command.c
Run: ./a.out fork.c
Output: file mode of fork.c 33188 of which is an ordinary file.
19
(b) AIM: Recurssively decend a directory hierarchy pointing a file
#include<stdio.h>
#include<dirent.h>
#include<errno.h>
#include<fcntl.h>
main(int argc,char *argv[])
{
struct dirent *direntp;
DIR *dirp;
if(argc!=2)
{
printf("ussage %s directory name \n",argv[0]);
return 1;
}
if((dirp=opendir(argv[1]))==NULL)
{
perror("Failed to open directory \n");
return 1;
}
while((direntp=readdir(dirp))!=NULL)
printf("%s\n",direntp->d_name);
while((closedir(dirp)==-1)&&(errno==EINTR));
return 0;
}
Compile: cc directory.c
Run: ./a.out ./
Output: fork.c
Wait.c
Execv.c
Execlp.c
Command.c
20
EXPERIMENT 3
OBJECTIVE
Write C programs to demonstrate various process related concepts.
(a) zombie process (b)orphan 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<unistd.h>
int main()
{
pid_t ret_value;
printf(“\n The process id is %d\n”,getpid());
ret_value=fork();
if(ret_value<0){
printf(“\n Fork Failure\n”);
}
elseif(ret_value==0)
{
//child process
printf(“\n child process\n”);
printf(“the process id is %d\n”,getpid());
//sleep(20);
}
Else{
21
//parent process
printf(“parent process\n”);
printf(“the process id is %d\n”,getpid());
sleep(30);
}
return 0;}
Compile:cc Zombie.c
Run: ./a.out
Output: The process id is 4394
parent process
the process id is 4394
child process
the process id is 4395
22
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.
23
Compile:cc orphan.c
Run: ./a.out
Output: Demonstration of orphan process
parent ID is 7035
parent of parent process is 3201
child ID is 7036
child parent ID is 1
EXPERIMENT 4
OBJECTIVE
Write C programs to demonstrate various thread related concepts
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.)
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
24
• 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
Naming convention :
• All routines begin with pthread_
• Pthreads API contains around 100 subroutines
• For portability, the pthread.h header file should be includes in each source file using the
Pthreads library
• Current POSIX standard is defined only for C language.
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:
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.
Terminating Threads - pthread_exit():
o There are several ways in which a thread may be terminated:
Threads returns normally from its starting routine. It's work is done.
Threads can make a call to the pthread_exit subroutine - whether its work is done or not.
The thread is canceled by another thread via the pthread_cancel routine.
The entire process is terminated due to making a call to either the exec() or exit()
25
If main() finishes first, without calling pthread_exit explicitly itself
o Cleanup: the pthread_exit () routine does not close files; any files opened inside the thread
will remain open after the thread is terminated.
Thread joining:
Syntax:
pthread_join (threadid, status)
26
exit(0);
}
27
(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;
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 */
/* wait we run the risk of executing an exit which will terminate */
/* the process and all threads before the threads have completed. */
pthread_join( thread1, NULL);
pthread_join( thread2, NULL);
exit(0);
}
void *functionC()
{
pthread_mutex_lock( &mutex1 );
counter++;
28
printf("Counter value: %d\n",counter);
pthread_mutex_unlock( &mutex1 );
}
Compile: cc Threadmutex1.c -lpthread
Run: ./a.out
Output: Counter value: 1
Counter value: 2
29
for(i=0;i<=n;i++)
{
if(i%2!=0)
{
oddarr[jo]=i;
oddsum=oddsum+i;
jo++;
}}}
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);
30
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);
}
31
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.)
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
32
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)
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.
What is Convoy Effect?
Convoy Effect is a situation where many processes, who need to use a resource for short time are
blocked by one process holding that resource for a long time.
This essentially leads to poor utilization of resources and hence poor performance.
Here we have simple formulae for calculating various times for given processes:
(a) AIM:To Implement First Come, First Serve (FCFS) Cpu Scheduling Algorithm
#include<stdio.h>
main()
{
int WT[10],BT[10],TA[10],TTA=0,TWT=0,AWT,ATA,n,i;
printf("enter the value of n");
scanf("%d",&n);
33
printf("enter BT of n process \n");
for(i=1;i<=n;i++)
scanf("%d",&BT[i]);
WT[1]=0;
TA[1]=BT[1]+WT[1];
for(i=2;i<=n;i++)
{
WT[i]=BT[i-1]+WT[i-1];
TA[i]=BT[i]+WT[i];
TWT=TWT+WT[i];
TTA=TTA+TA[i];
}
AWT=TWT/n;
ATA=TTA/n;
printf("Process no.\t Burst time\t Waiting time\t Turnaround time\n");
for(i=1;i<=n;i++)
{
printf("%d\t %d\t %d\t %d\t",i,BT[i],WT[i],TA[i]);
printf("\n");
}}
Compile: cc fcfs.c
Run: ./a.out
Output: Enter the value of n 3
Enter BT of n process
5
4
6
Process no. Burst time Waiting time Turnaround time
1 5 0 5
2 4 5 9
3 6 9 15
34
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
(b) AIM:To Implement Shortest Job First(SJF) Cpu Scheduling Algorithm
#include<stdio.h>
main()
{
int WT[10],BT[10],TA[10],TTA=0,TWT=0,AWT,pn[10],ATA,n,j,temp,i;
printf("enter the value of n");
scanf("%d",&n);
printf("enter BT of n process \n");
for(i=1;i<=n;i++)
{
scanf("%d",&BT[i]);
pn[i]=i;
}
for(i=1;i<n;i++)
for(j=i;j<=n;j++)
{
if(BT[i]>BT[j])
{
temp=BT[i];
BT[i]=BT[j];
BT[j]=temp;
temp=pn[i];
35
pn[i]=pn[j];
pn[j]=temp;
}
]
WT[1]=0;
TA[1]=BT[1]+WT[1];
for(i=2;i<=n;i++)
{
WT[i]=BT[i-1]+WT[i-1];
TA[i]=BT[i]+WT[i];
TWT=TWT+WT[i];
TTA=TTA+TA[i];
}
AWT=TWT/n;
ATA=TTA/n;
printf("Process no.\t Burst time\t Waiting time\t Turnaround time\n");
for(i=1;i<=n;i++)
{
printf("%d\t %d\t %d\t %d\t",i,BT[i],WT[i],TA[i]);
printf("\n");
}}
Compile: cc sjf.c
Run: ./a.out
Output: Enter the value of n 3
Enter BT of n process
5
4
7
Process no. Burst time Waiting time Turnaround time
1 4 0 4
2 5 4 9
3 7 9 16
36
DESCRIPTION: Priority Scheduling
Priority is assigned for each process.
Process with highest priority is executed first and so on.
Processes with same priority are executed in FCFS manner.
Priority can be decided based on memory requirements, time requirements or any other
resource requirement.
(c) AIM:To Implement PRIORITY Cpu Scheduling Algorithm
#include<stdio.h>
main()
{
int p[20],bt[20],pri[20], wt[20],tat[20],i, k, n, temp;
float wtavg, tatavg;
printf("Enter the number of processes --- ");
scanf("%d",&n);
for(i=0;i<n;i++)
{ p[i] = i;
printf("Enter the Burst Time & Priority of Process %d --- ",i);
scanf("%d %d",&bt[i], &pri[i]);
}
for(i=0;i<n;i++)
for(k=i+1;k<n;k++)
if(pri[i] > pri[k])
{
temp=p[i];
p[i]=p[k];
p[k]=temp;
temp=bt[i];
bt[i]=bt[k];
bt[k]=temp;
temp=pri[i];
pri[i]=pri[k];
pri[k]=temp
}
wtavg = wt[0] = 0;
37
tatavg = tat[0] = bt[0];
for(i=1;i<n;i++)
{
wt[i] = wt[i-1] + bt[i-1];
tat[i] = tat[i-1] + bt[i];
wtavg = wtavg + wt[i];
tatavg = tatavg + tat[i];
}
printf("\nPROCESS\t\tPRIORITY\tBURST TIME\tWAITING TIME\tTURNAROUND
TIME");
for(i=0;i<n;i++)
printf("\n%d \t\t %d \t\t %d \t\t %d \t\t %d ",p[i],pri[i],bt[i],wt[i],tat[i]);
printf("\nAverage Waiting Time is --- %f",wtavg/n);
printf("\nAverage Turnaround Time is --- %f",tatavg/n);
}
Compile: cc priority.c
Run: ./a.out
Output: Result: Enter the number of processes --- 5
Enter the Burst Time & Priority of Process 0 --- 10 3
Enter the Burst Time & Priority of Process 1 --- 1 1
Enter the Burst Time & Priority of Process 2 --- 2 4
Enter the Burst Time & Priority of Process 3 --- 1 5
Enter the Burst Time & Priority of Process 4 --- 5 2
38
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.
39
temp=q;
if(temp_bt[i]==0)
{
count++;
continue;
}
if(temp_bt[i]>q)
temp_bt[i]=temp_bt[i]-q;
else if(temp_bt[i]>=0)
{
temp=temp_bt[i];
temp_bt[i]=0;
}
x=x+temp;
tat[i]=x;
}
if(n==count)
break;
}
for(i=0;i<n;i++)
{
wt[i]=tat[i]-bt[i];
twt=twt+wt[i];
ttat=ttat+tat[i];
}
printf("\nProcess\t|Burst Time\t|Wait Time\t|Turn-Around Time");
for(i=0;i<n;i++)
{
printf("\n%d\t|%d\t\t|%d\t\t|%d",i,bt[i],wt[i],tat[i]);
}
printf("\n\nTotal waiting time is %f",twt);
40
printf("\nAverage waiting time is %f",twt/n);
printf("\n\nTotal turn around time is %f",ttat);
printf("\nAverage turn around time is %f\n\n",ttat/n);
}
Compile: cc roundrobin.c
Run: ./a.out
Output: ***** RR (ROUND ROBIN) SCHEDULING ******
Enter the number of processes 3
Enter the burst time of process0:6
Enter the burst time of process1:4
Enter the burst time of process2:2
Enter the time quantum
Process Burst Time Wait Time Turn-Around Time
0 6 6 12
1 4 6 10
2 2 0 6
41
EXPERIMENT 6
OBJECTIVE
Write C programs to simulate Intra & Inter-Process Communication (IPC) techniques:
(A) Pipes (B) Messages Queues (C) Shared Memory.
DESCRIPTION: pipes
To create a simple pipe with ‘C’, we make use of the pipe() system call. It takes a single
argument which is an array of two integers, and if successful, the array will contain two
new file descriptors to be used for the pipeline.
After creating a pipe, the process typically spawns a new process. (Also, the child inherits
the open file descriptors)
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. Visually speaking, the output of d1 becomes the input for fd().
Once again, all the data travelling through pipe moves through the kernel.
42
}
else
{
read(a[0],buff,3);
printf("parent received the message from child is %s \n",buff);
}
}
Compile: cc Pipes.c
Run: ./a.out
Output:child process message to parent is 15
Parent received the message from child is 15
43
DESCRIPTION: echo server using pipes
Pipe acts as a medium to transfer output of one process as input to another process.
The process will do the work and generate output. If the same output is required by the
second process, then we can repeat the process. But it is time consuming. So we prefer to
give output of first to second through the Inter Process Communication technique.
(a) AIM: To demonstrate echo server using pipes
#include<stdio.h>
main()
{
int pid,a[2],b[2],i=5;
char str[3],buff[3];
pipe(a);
pipe(b);
pid=fork();
if(pid==0)
{
i=i+10;
sprintf(str,"%d",i);
write(a[1],str,3);
sleep(5);
read(b[0],str,3);
printf("response from server is %s \n",str);
}
else
{
read(a[0],buff,3);
printf("request from client is %s \n",buff);
i=i+15;
sprintf(buff,"%d",i);
write(b[1],buff,3);
wait();}}
44
Compile: cc E_Pipes.c
Run: ./a.out
Output: request from client is 15
response from client is 15
request from server is 20
45
(B) AIM : To demonstrate basic operations with message queues
#include<stdio.h>
#include<sys/msg.h>
#include<sys/ipc.h>
#include<string.h>
main()
{
int pid,msgid;
char a[20],buf[20];
msgid=msgget((key_t)59,IPC_CREAT|0600);
pid=fork();
if(pid==0)
{
strcpy(a,"HELLO_CSE");
msgsnd(msgid,&a,10,0);
}
else
{
msgrcv(msgid,&buf,15,0,0);
printf("message from child is %s \n",buf);
}
}
Compile: cc MessageQ.c
Run: ./a.out
Output: message from child is HI
46
DESCRIPTION: echo server using message queues
Echo server is any program that provides some service or work. In message queues, a mail box is
created. OS should read and write program. Context switches makes program longer and therefore,
shared memory is used. In message queues, the syntax for creating and receiving is as follows:
Create:
int msgid = msgget( (key_t) 21, IPC_CREAT|0600);
Sending Message:
msgsnd( msqid, &mbuff, length, 0);
struct mbuff
{
char[10];
int type;
};
struct mbuff a1;
strcpy(a1.a, “CSE_OSLAB”);
a1.type = 1;
Receiving Message:
msgrcv( msqid, &buffer, length, type, 0);
47
{
strcpy(a,"1604-13-733-059");
msgsnd(msgid,&a,15,IPC_NOWAIT);
sleep(1);
msgrcv(msgid,&a,15,0,0);
printf("response from server is %s \n",a);
}
else
{
msgrcv(msgid,&buf,15,0,0);
printf("response from client is %s \n",buf);
strcpy(buf,"pass");
msgsnd(msgid,&buf,15,IPC_NOWAIT);
wait();
}}
Compile: cc E_MessageQ.c
Run: ./a.out
Output: response from client is1603-18-733-044
response from server is pass
48
DESCRIPTION: IPC using shared memory
Shared memory (shm) is also one of IPC (inter process communication) technique like pipes, but
pipes are use full to communicate parent and child process.
But here shared memory concept is supporting communication between any two independent
processes. Generally every shared memory is associated with a key. if process knows the key of
that shared memory, then it can attach to that shared memory and it will return a pointer to that
shared memory and we can read or write in to that shared memory using that pointer .
First Function:
int shmget(key_t key, size_t size, int flag);
First argument is the KEY of the shared memory.
Second argument is SIZE of the shared memory.
The flag is two types
IPC_CREAT| 0666,if we have to create the shared memory for the first time.
0666,if we have to just get the key of the shared memory which has been already created by any
other process.
if return value is > 0, success and return value = id of desired shm
= -1, failure
and we can not create shm with that key (already another shm is created with that key) or we can
not get the id of desired shm.
Second Function:
char* shmat(int shmid,char* shmaddr, int flag);
shmid is the return value of the shmget() function, here we have to pass it as first argument.
Generally shmaddr will be passed as NULL, and flag = 0.
Return value is pointer to desired shared memory segment. Thus we can read or write in to that
shared memory.
49
(C) AIM : Write a program to illustrate communication between processes using shared memory
//program to write data at the shared memory location
#include<stdio.h>
#include<sys/shm.h>
#include<sys/ipc.h>
int main()
{
char *s;
int shmid=shmget(1234,20,IPC_CREAT|0666);
s=shmat(shmid,NULL,0);
printf("Enter a msg: \n");
scanf("%s",s);
}
Compile: cc shared.c
Run: ./a.out
Output:Enter a msg: hello
50
EXPERIMENT 7
OBJECTIVE
Write C programs to simulate solutions to Classical Process Synchronization Problems:
(a) Dining Philosophers (b) Producer-Consumer (c) Readers-Writers
51
Semaphores are of two types:
1. Binary Semaphore – This is also known as mutex lock. It can have only two values – 0
and 1. Its value is initialized to 1. It is used to implement solution of critical section problem
with multiple processes.
2. Counting Semaphore – Its value can range over an unrestricted domain. It is used to
control access to a resource that has multiple instances.
process P[i]
while true do
{ HUNGRY;
PICKUP(CHOPSTICK[i], CHOPSTICK[i+1 mod 5]);
EAT;
PUTDOWN(CHOPSTICK[i], CHOPSTICK[i+1 mod 5])
}
(a) AIM: To implement Dining Philosopher’s Problem using semaphore
#include<stdio.h>
#include<pthread.h>
pthread_mutex_t chopstick[5];
pthread_t philosopher[5];
void* runner(void* arg)
{
int i=*(int*)arg;
printf("Philosopher %d is thinking \n",i);
sleep(2);
pthread_mutex_lock(&chopstick[i]);
pthread_mutex_lock(&chopstick[(i+1)%5]);
printf("philosopher %d is eating \n",i);
sleep(3);
pthread_mutex_unlock(&chopstick[i]);
pthread_mutex_unlock(&chopstick[(i+1)%5]);
52
printf("Philosopher %d finished eating \n",i);
}
int main()
{
int i;
for(i=0;i<5;i++)
{
pthread_create(&philosopher[i],NULL,runner,&i);
sleep(1);
}
for(i=0;i<5;i++)
pthread_join(philosopher[i],NULL);
}
53
DESCRIPTION: Producer Consumer problem
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.
54
(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)
55
{
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: cc ProducesConsumer.c
Run: ./a.out
Output: 1.Producer
2.Consumer
3.Exit
56
Enter your choice:1
Producer produces the item 1
Enter your choice:1
Producer produces the item 2
Enter your choice:1
Producer produces the item 3
Enter your choice:1
Buffer is full!!
Enter your choice:2
Consumer consumes item 3
Enter your choice:2
Consumer consumes item 2
Enter your choice:2
Consumer consumes item 1
Enter your choice:2
Buffer is empty!!
Enter your choice:3
57
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);
}
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)
58
{
//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);
}
59
(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);
}
main()
{
int i,b;
pthread_t rtid[5],wtid[5];
sem_init(&mutex,0,1);
60
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);
}
}
61
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.
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.
62
(a) AIM: To implement FIFO page replacement algorithms
#include<stdio.h>
main()
{
nt i, j, k, f, pf=0, count=0, rs[25], m[10], n;
printf("\n Enter the length of reference string -- ");
scanf("%d",&n);
printf("\n Enter the reference string -- ");
for(i=0;i<n;i++)
scanf("%d",&rs[i]);
printf("\n Enter no. of frames -- ");
scanf(“%d”,&f);
for(i=0;i<f;i++)
m[i]=-1;
printf("\n The Page Replacement Process is \n");
for(i=0;i<n;i++)
{
for(k=0;k<f;k++)
{
if(m[k]==rs[i])
break;
}
if(k==f)
{
m[count++]=rs[i];
pf++;
}
for(j=0;j<f;j++)
printf("\t%d",m[j]);
if(k==f)
printf("\tPF No. %d",pf);
printf("\n");
if(count==f)
63
count=0;
}
printf("\n The number of Page Faults using FIFO are %d",pf);
}
Compile: cc FIFO.c
Run: ./a.out
Output: Enter the length of reference string -- 20
Enter the reference string -- 7 0 1 2 0 3 0 4 2 3 0 3 2 1 2 0 1 7 0 1
Enter no. of frames -- 3
The Page Replacement Process is
7 -1 -1 PF No. 1
7 0 -1 PF No. 2
7 0 1 PF No. 3
2 0 1 PF No. 4
2 0 1
2 3 1 PF No. 5
2 3 0 PF No. 6
4 3 0 PF No. 7
4 2 0 PF No. 8
4 2 3 PF No. 9
0 2 3 PF No. 10
0 2 3
0 2 3
0 1 3 PF No. 11
0 1 2 PF No. 12
0 1 2
0 1 2
7 1 2 PF No. 13
7 0 2 PF No. 14
7 0 1 PF No. 15
64
(b) AIM: To implement LRU page replacement algorithms
#include<stdio.h>
main()
{
int i, j , k, min, rs[25], m[10], count[10], flag[25], n, f, pf=0, next=1;
printf("Enter the length of reference string -- ");
scanf("%d",&n);
printf("Enter the reference string -- ");
for(i=0;i<n;i++)
{
scanf("%d",&rs[i]);
flag[i]=0;
}
printf("Enter the number of frames -- ");
scanf("%d",&f);
for(i=0;i<f;i++)
{
count[i]=0; m[i]=-1;
}
printf("\nThe Page Replacement process is -- \n");
for(i=0;i<n;i++)
{
for(j=0;j<f;j++)
{
if(m[j]==rs[i])
{
flag[i]=1;
count[j]=next;
next++;}
}
if(flag[i]==0)
{
if(i<f)
{
m[i]=rs[i];
count[i]=next;
next++;
}
else
{
min=0;
65
for(j=1;j<f;j++)
if(count[min] > count[j]) min=j;
m[min]=rs[i];
count[min]=next;
next++;
}
pf++;
}
for(j=0;j<f;j++) printf("%d\t", m[j]);
if(flag[i]==0)
printf("PF No. -- %d" , pf);
printf("\n");
}
printf("\nThe number of page faults using LRU are %d",pf); }
Compile: cc LRU.c
Run: ./a.out
Output: Enter the length of reference string -- 20
Enter the reference string -- 7 0 1 2 0 3 0 4 2 3 0 3 2 1 2 0 1 7 0 1
Enter the number of frames – 3
The Page Replacement process is --
7 -1 -1 PF No. -- 1
7 0 -1 PF No. -- 2
7 0 1 PF No. -- 3
2 0 1 PF No. -- 4
2 0 1
2 0 3 PF No. -- 5
2 0 3
4 0 3 PF No. -- 6
4 0 2 PF No. -- 7
4 3 2 PF No. -- 8
0 3 2 PF No. -- 9
0 3 2
0 3 2
1 3 2 PF No. -- 10
1 3 2
1 0 2 PF No. -- 11
1 0 2
1 0 7 PF No. -- 12
1 0 7
1 0 7
The number of page faults using LRU are 12
66
EXPERIMENT 9
OBJECTIVE
Write a C program to simulate Bankers algorithm for the purpose of deadlock avoidance.
DESCRIPTION:
In a multiprogramming environment, several processes may compete for a finite number of
resources. A process requests resources; if the resources are not available at that time, the process
enters a waiting state. Sometimes, a waiting process is never again able to change state, because
the resources it has requested are held by other waiting processes. This situation is called a
deadlock. Deadlock avoidance is one of the techniques for handling deadlocks. This approach
requires that the operating system be given in advance additional information concerning which
resources a process will request and use during its lifetime. With this additional knowledge, it can
decide for each request whether or not the process should wait. To decide whether the current
request can be satisfied or must be delayed, the system must consider the resources currently
available, the resources currently allocated to each process, and the future requests and releases of
each process. Banker’s algorithm is a deadlock avoidance algorithm that is applicable to a system
with multiple instances of each resource type.
67
AIM: To implement Bankers algorithm for the purpose of deadlock avoidance.
#include<stdio.h>
struct file
{
int all[10];
int max[10];
int need[10];
int flag;
};
void main()
{
struct file f[10];
int fl;
int i, j, k, p, b, n, r, g, cnt=0, id, newr;
int avail[10],seq[10];
clrscr();
printf("Enter number of processes -- ");
scanf("%d",&n);
printf("Enter number of resources -- ");
scanf("%d",&r);
for(i=0;i<n;i++)
{
printf("Enter details for P%d",i);
printf("\nEnter allocation\t -- \t");
for(j=0;j<r;j++)
scanf("%d",&f[i].all[j]);
printf("Enter Max\t\t -- \t");
for(j=0;j<r;j++)
scanf("%d",&f[i].max[j]);
f[i].flag=0;
}
68
printf("\nEnter Available Resources\t -- \t");
for(i=0;i<r;i++)
scanf("%d",&avail[i]);
printf("\nEnter New Request Details -- ");
printf("\nEnter pid \t -- \t");
scanf("%d",&id);
printf("Enter Request for Resources \t -- \t");
for(i=0;i<r;i++)
{
scanf("%d",&newr);
f[id].all[i] += newr;
avail[i]=avail[i] - newr;
}
for(i=0;i<n;i++)
{
for(j=0;j<r;j++)
{
f[i].need[j]=f[i].max[j]-f[i].all[j];
if(f[i].need[j]<0)
f[i].need[j]=0;
}
}
cnt=0;
fl=0;
while(cnt!=n)
{
g=0;
for(j=0;j<n;j++)
{
if(f[j].flag==0)
69
{
b=0;
for(p=0;p<r;p++)
{
if(avail[p]>=f[j].need[p])
b=b+1;
else
b=b-1;
}
if(b==r)
{
printf("\nP%d is visited",j);
seq[fl++]=j;
f[j].flag=1;
for(k=0;k<r;k++)
avail[k]=avail[k]+f[j].all[k];
cnt=cnt+1;
printf("("); for(k=0;k<r;k++)
printf("%3d",avail[k]);
printf(")");
g=1;
} }}
if(g==0)
{
printf("\n REQUEST NOT GRANTED -- DEADLOCK OCCURRED");
printf("\n SYSTEM IS IN UNSAFE STATE");
goto y;
}}
printf("\nSYSTEM IS IN SAFE STATE");
printf("\nThe Safe Sequence is -- (");
for(i=0;i<fl;i++)
70
printf("P%d ",seq[i]);
printf(")");
y: printf("\nProcess\t\tAllocation\t\tMax\t\t\tNeed\n");
for(i=0;i<n;i++)
{
printf("P%d\t",i);
for(j=0;j<r;j++)
printf("%6d",f[i].all[j]);
for(j=0;j<r;j++)
printf("%6d",f[i].max[j]);
for(j=0;j<r;j++)
printf("%6d",f[i].need[j]);
printf("\n");
}
getch();}
Compile: cc Bankers.c
Run: ./a.out
Output: Enter number of processes – 5
Enter number of resources – 3
Enter details for P0
Enter allocation -- 0 1 0
Enter Max -- 7 5 3
Enter details for P1
Enter allocation -- 2 0 0
Enter Max -- 3 2 2
Enter details for P2
Enter allocation -- 3 0 2
Enter Max -- 9 0 2
Enter details for P3
Enter allocation -- 2 1 1
Enter Max -- 2 2 2
71
Enter details for P4
Enter allocation -- 0 0 2
Enter Max -- 4 3 3
Enter Available Resources -- 3 3 2
Enter New Request Details –
Enter pid -- 1
Enter Request for Resources -- 1 0 2
P1 is visited( 5 3 2)
P3 is visited( 7 4 3)
P4 is visited( 7 4 5)
P0 is visited( 7 5 5)
P2 is visited( 10 5 7)
SYSTEM IS IN SAFE STATE
72
EXPERIMENT 10
OBJECTIVE
Write a C program to simulate FCFS disk scheduling algorithms
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. This algorithm is intrinsically fair, but it
generally does not provide the fastest service.
#include<stdio.h>
main()
{
int t[20], n, I, j, tohm[20], tot=0;
float avhm;
clrscr();
printf(“enter the no.of tracks”);
scanf(“%d”,&n);
printf(“enter the tracks to be traversed”);
for(i=2;i<n+2;i++)
scanf(“%d”,&t[i]);
for(i=1;i<n+1;i++)
{
tohm[i]=t[i+1]-t[i];
if(tohm[i]<0)
tohm[i]=tohm[i]*(-1);
}
for(i=1;i<n+1;i++)
tot+=tohm[i];
avhm=(float)tot/n;
73
printf(“Tracks traversed\tDifference between tracks\n”);
for(i=1;i<n+1;i++)
printf(“%d\t\t\t%d\n”,t[i],tohm[i]);
printf("\nAverage header movements:%f",avhm);
getch();
}
Compile: cc fcfs_disk.c
Run: ./a.out
Output: Enter no.of tracks:9
Enter track position:55 58 60 70 18 90 150 160 184
OUTPUT
Tracks traversed difference between tracks
55 45
58 3
60 2
70 10
18 52
90 72
150 60
160 10
184 24
Average header movements:30.888889
74