0% found this document useful (0 votes)
17 views69 pages

OS Record

Uploaded by

owaismohammed203
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)
17 views69 pages

OS Record

Uploaded by

owaismohammed203
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

Operating Systems Lab

PROGRAM: 1(A)

AIM: Program to demonstrate the usage of file related system calls

Problem Definition: To demonstrate usage of system calls-open(), creat(), read(), write(),


close() for file management.
Problem 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

Here, a program to copy the contents of one file into another is used to demonstrate the
usage of file related system calls.

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

Syntax:
open()
#include<fcntl.h>
int open(const char *path,int oflag);
close()
#include <unistd.h>
int close(int fildes);
read()
#include<sys/types.h>
size_t read(int fildes,void *buf,size_t nbyte);
write()
#include<sys/types.h>
size_t write(int fildes, const void *buf, size_t nbyte);

Algorithm:
1: open file1 in read mode.
2: open or create file2 and open it in write mode
3: Read data from file1 into a buffer.
4: Write data to file2 from buffer.
5: Close the files.
6: Open file2 for Read only
7: Read data from file into buffer.
8: Display buffer data to standard output
9: Close the file.
Program:

Read():

#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>
#include<unistd.h>
#include<sys/stat.h>
#define BUFSIZE 1024
int main()
{
int fd1,n;
char buf[BUFSIZE];
fd1=open("[Link]",O_RDONLY);
if(fd1<0)
{
perror("Error");
exit(1);
}
n=read(fd1,buf,BUFSIZE);
if(n==-1)
{
perror("Error");
exit(1);
}
printf("n=%d",n);
close(fd1);
}

Output:
Open():

#include<stdio.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
int fd1=open("[Link]", O_RDONLY);
int fd2=open("[Link]", O_RDONLY);
if((fd1||fd2)==-1)
{
perror("Error in Opening");
exit(1);
}
printf("\nfd1=%d\tfd2=%d",fd1,fd2);
close(fd1);
close(fd2);
}

Output:
Write():

#include<stdio.h>
#include<fcntl.h>
#include<unistd.h>
int main()
{
int fd1,fd2,n;
char buf[25];
fd1=open("[Link]",O_RDONLY);
fd2=open("[Link]",O_WRONLY/O_APPEND);
while((n=read(fd1,buf,20))!=0)
{
write(fd2,buf,n);
}
close(fd1);
close(fd2);
}

Output:
Copy():

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/stat.h>
int main(int argc,char* argv[])
{
int fd1,fd2,n;
char buf[25];
fd1=open(argv[1], O_RDONLY);
fd2=open(argv[2], O_WRONLY|O_CREAT,0644);
if((fd1<0||fd2)<0)
{
printf("Error");
exit(1);
}
while(1)
{
int n=read(fd1,buf,1);
write(fd2,buf,1);
if(n<=0)
break;
}
close(fd1);
close(fd2);

fd2=open(argv[2], O_RDONLY);
if(fd2<0)
{
printf("Error");
exit(1);
}
while(1)
{
n=read(fd2,buf,1);
if(n<=0)
break;
write(1,buf,1);
}
close(fd2);
}

Output:
Operating Systems Lab
PROGRAM: 1(B)

AIM: Program to reposition the file offset on Linux using lseek( ) system call

Problem Definition: To write the program to implement the system call lseek( ).
Problem Description: lseek() system call is used to reposition the file offset.

System Calls Used: lseek()—set file offset

Syntax:
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);

This function return lseek() returns the resulting offset location as measured in bytes from the
beginning of the file. On error, the value (off_t) -1 is returned

lseek() repositions the file offset of the open file description associated with the file descriptor
fd to the argument offset according to the directive whence as follows:

SEEK_SET
The file offset is set to offset bytes.

SEEK_CUR
The file offset is set to its current location plus offset bytes.

SEEK_END
The file offset is set to the size of the file plus offset bytes.

Algorithm:

1: Open the file using open


2: Read the contents in buffer.
3: Write the contents on screen.
4: Using lseek to change offset position.
5: Verify change by displaying output on screen.
Program:

lseek() with SEEK_SET:

#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>
#include<unistd.h>
#include<sys/stat.h>
int main()
{
int fd;
char buf[20];
fd=open("[Link]",O_RDONLY);
if(fd<0)
{
printf("Error");
exit(1);
}
read(fd,buf,10);
write(1,buf,10);
printf("\n");
lseek(fd,10,SEEK_SET);
read(fd,buf,10);
write(1,buf,10);
printf("\n");
close(fd);
}

Output:
lseek() with SEEK_CUR:

#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>
#include<unistd.h>
#include<sys/stat.h>
int main()
{
int fd;
char buf[20];
fd=open("[Link]",O_RDONLY);
if(fd<0)
{
printf("Error");
exit(1);
}
read(fd,buf,10);
write(1,buf,10);
printf("\n");
lseek(fd,10,SEEK_CUR);
read(fd,buf,10);
write(1,buf,10);
printf("\n");
close(fd);
}

Output:
lseek() with SEEK_END:

#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>
#include<unistd.h>
#include<sys/stat.h>
int main()
{
int fd;
char buf[20];
fd=open("[Link]",O_RDWR);
if(fd<0)
{
printf("Error");
exit(1);
}
read(fd,buf,10);
write(1,buf,10);
printf("\n");
lseek(fd,-11,SEEK_END);
read(fd,buf,10);
write(1,buf,10);
close(fd);
}

Output:
Operating Systems Lab
PROGRAM: 1(C)

AIM: Program to get the attributes of a file on Linux using stat( ) system call

Problem Definition: To write the program to implement the system call stat( ).
Problem Description: stat() system call is used to get file attributes.

System Calls Used: stat()--get file status

Syntax:
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *pathname, struct stat *statbuf);

This function return information about a file, in the buffer pointed to by statbuf
stat returns 0 if successful and –1 otherwise

The stat structure contains the following fields:

struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* Inode number */
mode_t st_mode; /* File type and mode */
nlink_t st_nlink; /* Number of hard links */
uid_t st_uid; /* User ID of owner */
gid_t st_gid; /* Group ID of owner */
dev_t st_rdev; /* Device ID (if special file) */
off_t st_size; /* Total size, in bytes */
blksize_t st_blksize; /* Block size for filesystem I/O */
blkcnt_t st_blocks; /* Number of 512B blocks allocated */ }

Algorithm:

1: Retrieve the attributes of the file using stat


2: The attributes of the file are Userid, groupid, device name, inode no, No of Hard links, Size in
bytes, Block size, No. of blocks allocated, Time of last access, Last modification and last status
change, Type of file, user and group privileges ( Read Write and Execute Permissions)
Program:

Stat:

#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>
#include<unistd.h>
#include<sys/stat.h>
#include<time.h>
int main(int argc, char* argv[])
{
int fd;
struct stat buf;
fd = stat(argv[1],&buf);
if(fd<0)
{
perror("Error");
exit(1);
}
printf("Inode no=%d\n",buf.st_ino);
printf("user id=%d\n",buf.st_uid);
printf("grp id=%d\n",buf.st_gid);
printf("No of links=%d\n",buf.st_nlink);
printf("size=%d\n",buf.st_size);
printf("Last status change =%s",ctime(&buf.st_ctime));
printf("Last file accessed =%s",ctime(&buf.st_atime));
printf("Last file modified =%s",ctime(&buf.st_mtime));

Output:
Operating Systems Lab
PROGRAM: 2(A)
AIM: Program to demonstrate the usage of file related system calls

Problem Definition: To demonstrate fork () (process creation), getpid(), getppid(), wait()


and sleep() system call
Problem Description: fork() is used to create a new process. getpid() is used to get the
process id. getppid() is used to get the parent process id. wait() is used to wait for process to
change state. sleep() is used to sleep/suspend execution for a specified number of seconds

Syntax:
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
On success, the PID of the child process is returned in the parent, and 0 is returned in the child.
On failure, -1 is returned in the parent, no child process is created, and errno is set appropriately.

Syntax:#include <sys/types.h>
#include <unistd.h>
pid_t getpid(void);
pid_t getppid(void);

getpid() returns the process ID (PID) of the calling process.


getppid() returns the process ID of the parent of the calling process. This will be either the ID of
the process that created this process using fork(), or, if that process has already terminated, the ID
of the process to which this process has been reparented (init(1)).

#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *wstatus);
On success returns the process ID of the terminated child;
On error, -1 is returned

#include <unistd.h>
unsigned int sleep(unsigned int seconds);
Zero if the requested time has elapsed, or the number of seconds left to sleep, if the call was
interrupted by a signal handler

fork() creates a new process by duplicating the calling process. The new process is referred to as the
child process. The calling process is referred to as the parent process.
The child process and the parent process run in separate memory spaces. At the time of fork() both
memory spaces have the same content. Memory writes, file mappings, and unmappings performed
by one of the processes do not affect the other.
After fork returns, the parent process and child process now have different PIDs. At this
point, there are two processes with practically identical constitute, and they both continue execution
at the statement following fork(). To be able to distinguish between the parent and the child process,
fork returns with two values: Zero in the child process. The PID of the child is returned in the
parent process.
System Calls Used:
fork ( ) is used to create new process. The new process consists of a copy of the addressspace of
the original process. The value of process id for the child process is zero, whereas the value of
process id for the parent is an integer value greater than zero.

The wait() system call suspends execution of the calling thread until one of its children
terminates. The parent waits for the child process to complete using the wait system call. The
wait system call returns the process identifier of a terminated child, so that the parent can tell
which of its possibly many children has terminated.

sleep() causes the calling thread to sleep either until the number of real-time seconds specified in
seconds have elapsed or until a signal arrives which is not ignored.
.
Program:

Fork:

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

int main()
{
int pid;
printf("demo of fork()");
pid=fork();
//printf("demo of fork()");
if(pid<0)
{
exit(1);
}
else if(pid==0)
{
printf("I am a child process\n");
printf("my id=%d\n",getpid());
printf("my parent id=%d\n",getppid());
}
else
{
printf("I am a parent process\n");
printf("my id=%d\n",getpid());
printf("my parent id=%d\n",getppid());
printf("my child id=%d\n",pid);
}
}

Output:
Operating Systems Lab

PROGRAM: 2(B)
AIM: Program to demonstrate orphan process

Problem Definition: To demonstrate creation of an orphan process


Problem Description: The process whose parent process has finished (Completed
execution) or terminated and do not exists in the process table is called orphan process. Usually,
a parent process waits for its child to terminate or finish their job and report to it after execution
but if he fails to do so it results in the Orphan process.
In most cases, the Orphan process is immediately adopted by the init process (a very first process
of the system with pid=1).

Hence to create such a process a child is created first and it is made to sleep for some amount of
time. This allows the parent to complete its execution first, thus resulting in the creation of an
orphan process.

System Calls Used: fork(), sleep(), getpid(), getppid()

Syntax:#include <sys/types.h>
#include <unistd.h>
pid_t getpid(void);
pid_t getppid(void);
getpid() returns the process ID (PID) of the calling process.
getppid() returns the process ID of the parent of the calling process. This will be either the ID of
the process that created this process using fork(), or, if that process has already terminated, the ID
of the process to which this process has been reparented (init(1)).

Algorithm:
1. Create a child process
2. Child process is suspended for some time so that the parent process terminates to
demonstrate an orphan process
3. The init process becomes the parent of the orphan process
Program:

Orphan:
#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>
#include<unistd.h>
#include<sys/types.h>

int main()
{
int pid;
printf("demo of fork()");
pid=fork();
//printf("demo of fork()");
if(pid<0)
{
exit(1);
}
else if(pid==0)
{
sleep(2);
printf("I am a child process\n");
printf("my id=%d\n",getpid());
printf("my parent id=%d\n",getppid());
}
else
{
printf("I am a parent process\n");
printf("my id=%d\n",getpid());
printf("my parent id=%d\n",getppid());
printf("my child id=%d\n",pid);
}
}

Output:
Operating Systems Lab
PROGRAM: 2(C)
AIM: Program to demonstrate zombie process

Problem Definition: To demonstrate creation of an zombie process


Problem Description: A terminated process is said to be a zombie or defunct until the
parent does wait() on the child.
∙ When a process terminates all of the memory and resources associated with it are
deallocated so they can be used by other processes.
∙ However, the exit status is maintained in the PCB until the parent picks up the exit status
using wait() and deletes the PCB.
∙ A child process always first becomes a zombie.

∙ In most cases, under normal system operation zombies are immediately waited on by their
parent.
∙ Processes that stay zombies for a long time are generally an error and cause a resource leak.

Hence to create such a process child terminates before the parent does wait on the child and
becomes a zombie process.

System Calls Used: fork(), sleep(), system(ps -l)

Algorithm:
1. Create a child process
2. Parent process is suspended for some time so that the child process terminates to demonstrate
a zombie process
Program:

Zombie:
#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>
#include<unistd.h>
#include<sys/stat.h>

int main()
{
int pid;
printf("demo of fork()");
pid=fork();
//printf("demo of fork()");
if(pid<0)
{
exit(1);
}
else if(pid==0)
{
system("ps -l");
printf("I am a child process\n");
printf("my id=%d\n",getpid());
printf("my parent id=%d\n",getppid());
}
else
{
sleep(2);
system("ps -l");
printf("I am a parent process\n");
printf("my id=%d\n",getpid());
printf("my parent id=%d\n",getppid());
printf("my child id=%d\n",pid);
}
}

Output:
Operating Systems Lab
Program: 3(A)
AIM: Program to implement the concept of threads (Single Thread)

Problem Definition: Program for demonstrating creation and manipulation of thread.


Problem Description: A thread is a single sequence stream within in a process. Because
threads have some of the properties of processes, they are sometimes called lightweight
processes. POSIX Threads (or Pthreads) is a POSIX standard for threads.
Thread operations include thread creation, termination, synchronization (joins, blocking),
scheduling, data management and process interaction.

System Calls Used: pthread_create(), pthread_join(), pthread_exit()

pthread_create - create a new thread

Syntax:
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)
(void *), void *arg);

The pthread_create() function starts a new thread in the calling process. The new thread starts
execution by invoking start_routine(); arg is passed as the sole argument of start_routine(). The
attr argument points to a pthread_attr_t structure whose contents are used at thread creation time
to determine attributes for the new thread; If attr is NULL, then the thread is created with default
attributes. Before returning, a successful call to pthread_create() stores the ID of the new thread
in the buffer pointed to by thread; this identifier is used to refer to the thread in subsequent calls
to other pthreads functions.

pthread_join - join with a terminated thread


Syntax:
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
On success, pthread_join() returns 0; on error, it returns an error number.
The pthread_join() function waits for the thread specified by thread to terminate. If that thread has already
terminated, then pthread_join() returns immediately. If retval is not NULL, then pthread_join() copies the exit
status of the target thread

pthread_exit - terminate calling thread


Syntax:
#include <pthread.h>
void pthread_exit(void *retval);
The pthread_exit() function terminates the calling thread and returns a value via retval that (if the thread is
joinable) is available to another thread in the same process that calls pthread_join.

Algorithm:
1: Start the program.
2: Use pthread_create() to create a new thread. Specify the name of the routine within it. 3: Use
pthread_join() to synchronize.
4: Print messages and sleep for random time.
5: Within routine print some messages and sleep. Then use pthread_exit to terminate the thread.
Program:

Thread:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<pthread.h>

void *run();
int main()
{
int i,ret;
pthread_t t;
ret=pthread_create(&t,NULL,run,0);
if(ret==-1)
{
printf("Error");
exit(1);
}
for(i=0;i<=4;i++)
{
printf("Inside Main\n");
sleep(2);
}
}

void *run()
{
int i;
for(i=0;i<=4;i++)
{
printf("Inside Thread\n");
sleep(2);
}
pthread_exit(0);
}

Output:
pthread_join():

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

void *run();
int main()
{
int i,ret;
pthread_t t;
ret=pthread_create(&t,NULL,run,0);
if(ret==-1)
{
printf("Error");
exit(1);
}
pthread_join(t,0);
for(i=0;i<=4;i++)
{
printf("Inside Main\n");
sleep(2);
}
}

void *run()
{
int i;
for(i=0;i<=4;i++)
{
printf("Inside Thread\n");
sleep(2);
}
pthread_exit(0);
}

Output:
Operating Systems Lab
Program: 3(B)
AIM: Program to implement the concept of multithreading

Problem Definition: Program for demonstrating creation and manipulation of multiple


threads.
Problem Description: A thread is a single sequence stream within in a process. Because
threads have some of the properties of processes, they are sometimes called lightweight
processes. POSIX Threads (or Pthreads) is a POSIX standard for threads.
Thread operations include thread creation, termination, synchronization (joins, blocking),
scheduling, data management and process interaction.

System Calls Used: pthread_create(), pthread_join(), pthread_exit()


pthread_create - create a new thread

Syntax:
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)
(void *), void *arg);

The pthread_create() function starts a new thread in the calling process. The new thread starts
execution by invoking start_routine(); arg is passed as the sole argument of start_routine(). The
attr argument points to a pthread_attr_t structure whose contents are used at thread creation time
to determine attributes for the new thread; If attr is NULL, then the thread is created with default
attributes. Before returning, a successful call to pthread_create() stores the ID of the new thread
in the buffer pointed to by thread; this identifier is used to refer to the thread in subsequent calls
to other pthreads functions.

pthread_join - join with a terminated thread


Syntax:
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
On success, pthread_join() returns 0; on error, it returns an error number.
The pthread_join() function waits for the thread specified by thread to terminate. If that thread
has already terminated, then pthread_join() returns immediately. If retval is not NULL, then
pthread_join() copies the exit status of the target thread

pthread_exit - terminate calling thread


Syntax:
#include <pthread.h>
void pthread_exit(void *retval);
The pthread_exit() function terminates the calling thread and returns a value via retval that (if the
thread is joinable) is available to another thread in the same process that calls pthread_join.
Algorithm:
1: Start the program.
2: Use pthread_create() to create multiple threads. Specify the name of the routines within it. 3: Use
pthread_join() to synchronize the various threads.
4: Print messages and sleep for random time.
5: Within routine print some messages and sleep. Then use pthread_exit to terminate appropriate thread.
Program:

Multithreading:

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

void *run1();
void *run2();
void *run3();
int main()
{
int i,ret1,ret2,ret3;
pthread_t t1;
pthread_t t2;
pthread_t t3;
ret1=pthread_create(&t1,NULL,run1,0);
if(ret1==-1)
{
printf("Error");
exit(1);
}
pthread_join(t1,0);

ret2=pthread_create(&t2,NULL,run2,0);
if(ret2==-1)
{
printf("Error");
exit(1);
}
pthread_join(t2,0);

ret3=pthread_create(&t3,NULL,run3,0);
if(ret3==-1)
{
printf("Error");
exit(1);
}
pthread_join(t3,0);

for(i=0;i<=4;i++)
{
printf("Inside Main\n");
sleep(2);
}
}
void *run1()
{
int i;
for(i=0;i<=4;i++)
{
printf("Inside Thread1\n");
sleep(2);
}
pthread_exit(0);
}

void *run2()
{
int i;
for(i=0;i<=4;i++)
{
printf("Inside Thread2\n");
sleep(2);
}
pthread_exit(0);
}

void *run3()
{
int i;
for(i=0;i<5;i++)
{
printf("Inside Thread3\n");
sleep(2);
}
pthread_exit(0);
}

Output:
Operating Systems Lab
Program: 4(A)
AIM: Program to simulate CPU scheduling algorithm for first come first
serve scheduling.

Problem Definition: To write a program to calculate wait time and turnaround time of
processes using non preemptive FCFS algorithm.
Problem Description: Assume all the processes arrive at the same time.
For FCFS scheduling algorithm, read the number of processes/jobs in the system, their CPU
burst times. The scheduling is performed on the basis of arrival time of the processes irrespective
of their other parameters. Each process will be executed according to its arrival time. Calculate
the waiting time and turnaround time of each of the processes accordingly.

Algorithm:

1. Start the program.


2. Get the number of processes and their burst time.
3. Initialize the waiting time for first process as 0.
[Link] wait time, for(i=1; i<n; i++), which is the sum of wait time and burst time of
previous process, wt[i]=wt[i-1]+bt[i-1].
5. The waiting time of all the processes is summed then average value time is calculated. 6.
Calculate turnaround time, for(i=0; i<=n; i++), which is the sum of wait time and burst time of
the process, tat[i]=wt[i]+bt[i].
7. Waiting time and turnaround time of each process and average times are displayed
8. Stop the program
Program:

FCFS:

#include<stdio.h>

int main()
{
int
n,i,j,k,l,AT[10]={0},BT[10]={0},CT[10]={0},TAT[10]={0},WT[10]={0};
float totalTAT=0;
float totalWT=0;
printf("Enter no. of Processes:");
scanf("%d",&n);

//AT and BT
for(i=1;i<=n;i++)
{
printf("Enter AT for P[%d]:",i);
scanf("%d",&AT[i]);
printf("Enter BT for P[%d]:",i);
scanf("%d",&BT[i]);
}

//CT
int sum=AT[0];
for(j=1;j<=n;j++)
{
sum=sum+BT[j];
CT[j]=sum;
}

//TAT
for(k=1;k<=n;k++)
{
TAT[k]=CT[k]-AT[k];
totalTAT=totalTAT+TAT[k];
}

//WT
for(k=1;k<=n;k++)
{
WT[k]=TAT[k]-BT[k];
totalWT=totalWT+WT[k];
}

printf("P\tAT\tBT\tCT\tTAT\tWT\n");
for(i=1;i<=n;i++)
{
printf("P%d\t%d\t%d\t%d\t%d\t%d\n",i,AT[i],BT[i],CT[i],TAT[i],WT[i]);
}
printf("Average TAT = %f\n",totalTAT/n);
printf("Average WT = %f\n",totalWT/n);
}

Output:
Operating Systems Lab
Program: 4(B)
AIM: Program to simulate CPU scheduling algorithm for Shortest Job First
Scheduling.

Problem Definition: To write a program to calculate wait time and turnaround time of
processes using non preemptive SJF algorithm.
Problem Description: Assume all the processes arrive at the same time.
For SJF scheduling algorithm, read the number of processes/jobs in the system, their CPU burst
times. Arrange all the jobs in order with respect to their burst times. There may be two jobs in
queue with the same execution time, and then FCFS approach is to be performed. Each process
will be executed according to the length of its burst time. Then calculate the waiting time and
turnaround time of each of the processes accordingly.

Algorithm:

1. Start the program. Get the number of processes and their burst time.
2. Sort the processes according to their burst time. for(i=0; i<n; i++) and within that loop use
another loop for(j=i+1; j<n; j++), if(bt[j]<bt[i]) then use temp to swap i & j. 3. Initialize the
waiting time for first process as 0.
4. Calculate wait time, for(i=1; i<n; i++), which is the sum of current process wait time and burst
time of previous process. wt[i]=wt[i]+bt[i-1].
5. The waiting time of all the processes is summed then average value time is calculated. 6.
Calculate turnaround time, for(i=0; i<n; i++), which is the sum of wait time and burst time of the
process, tat[i]=wt[i]+bt[i].
7. Waiting time and turnaround time of each process and average times are displayed
8. Stop the program
Program:

SJF:
#include<stdio.h>
int main()
{
int
n,i,j,k,T,P[10],AT[10]={0},BT[10]={0},CT[10]={0},TAT[10]={0}
,WT[10]={0};
float totalTAT=0;
float totalWT=0;
printf("Enter no. of Processes:");
scanf("%d",&n);

//AT and BT
for(i=0;i<n;i++)
{
P[i]=i+1;
printf("Enter AT for P[%d]:",i+1);
scanf("%d",&AT[i]);
printf("Enter BT for P[%d]:",i+1);
scanf("%d",&BT[i]);
}

//Sort according to BT
for(i=0;i<n;i++)
{
for(j=0;j<(n-i-1);j++)
{
if(BT[j]>BT[j+1])
{
T=BT[j];
BT[j]=BT[j+1];
BT[j+1]=T;
T=P[j];
P[j]=P[j+1];
P[j+1]=T;
T=AT[j];
AT[j]=AT[j+1];
AT[j+1]=T;
}
}
}

//CT
int sum=AT[0];
for(j=0;j<n;j++)
{
sum=sum+BT[j];
CT[j]=sum;
}

//TAT
for(k=0;k<n;k++)
{
TAT[k]=CT[k]-AT[k];
totalTAT=totalTAT+TAT[k];
}

//WT
for(k=0;k<n;k++)
{
WT[k]=TAT[k]-BT[k];
totalWT=totalWT+WT[k];
}
printf("P\tAT\tBT\tCT\tTAT\tWT\n");
for(i=0;i<n;i++)
{
printf("P%d\t%d\t%d\t%d\t%d\t%d\n",P[i],AT[i],BT[i],
CT[i],TAT[i],WT[i]);
}
printf("Average TAT = %f\n",totalTAT/n);
printf("Average WT = %f\n",totalWT/n);
}

Output:
Operating Systems Lab
Program: 4(C)
AIM: Program to simulate CPU scheduling algorithm for round robin
Scheduling.

Problem Definition: To write a program to calculate wait time and turnaround time of
processes using round robin scheduling algorithm.
Problem Description: Assume all the processes arrive at the same time.
For round robin scheduling algorithm, read the number of processes/jobs in the system, their
CPU burst times, and the size of the time slice. Time slices are assigned to each process in equal
portions and in circular order, handling all processes execution. This allows every process to get
an equal chance. Calculate the waiting time and turnaround time of each of the processes
accordingly.

Algorithm:

1. Start the program. Get the number of process and their burst time.
2. Get Time Slice value.
3. Initialize the remaining time of each process with their burst times.
3. Schedule the processes as
if remaining bursttime > time slice.
Turnaround time is updated.
The remaining burst time of each process is calculated
else update remaining time for that process as 0. And calculate turnaround time. 4.
Calculate wait time as wt[i]=tat[i]-bt[i].
5. The average waiting time for each process and average turnaround times are calculated and
displayed.
6. Stop the program.
Program:

Round Robin:
#include<stdio.h>
int main()
{
int n,BT[10],TAT[10],WT[10],RT[10],c=0,ts=2,t=0;
float totalTAT=0, totalWT=0;
printf("Enter no. of process:");
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
//printf("Enter AT of P%d:",i+1);
//scanf("%d",&AT[i]);
printf("Enter BT of P%d:",i);
scanf("%d",&BT[i]);
}
for(int i=1;i<=n;i++)
RT[i]=BT[i];
while(1)
{
for(int i=1;i<=n;i++)
if(RT[i]>0)
{
if(RT[i]>ts)
{
t+=ts;
RT[i]-=ts;
}
else
{
t+=RT[i];
RT[i]=0;
TAT[i]=t;
c++;
}
}

if(c==n)
{
break;
}
}
for(int i=1;i<=n;i++)
{
WT[i]=TAT[i]-BT[i];
}
for(int i=1;i<=n;i++)
{
totalTAT+=TAT[i];
totalWT+=WT[i];
}
float aWT=totalWT/n;
float aTAT=totalTAT/n;

printf("\nP\tBT\tTAT\tWT\n\n");
for(int i=1;i<=n;i++)
{
printf("P%d\t%d\t%d\t%d\n",i,BT[i],TAT[i],WT[i]);
}
printf("\nAverage TAT=%f",aTAT);
printf("\nAverage WT=%f",aWT);
printf("\n");
}

Output:
Operating Systems Lab
Program: 5(A)
AIM: Program to demonstrate IPC using Unnamed Pipes
Problem Definition: To implement two-process communication through Echo server
application using unnamed pipes.
Problem 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. Visually speaking, the output of first becomes the input for second. Once again, all the
data travelling through pipe moves through the kernel.

Algorithm:

1. Create two pipes pipe1 and pipe2


2. Create a child process using fork.
3. Child writes to pipe1 and waits for response from parent
4. Parent reads data from pipe1 and writes to pipe2 for child to read
5. Child reads data written by parent to pipe2 through read end of pipe2 and displays on console.
Program:

Unnamed Pipe:

#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>
#include<stdlib.h>
#include<string.h>
int main()
{
int a[2],pid;
char str[20],buf[20];
pipe(a);
pid=fork();

if(pid<0)
{
exit(1);
}

//child
if(pid==0)
{
strcpy(str,"Demo of Pipes\n");
write(a[1],str,strlen(str)+1);
printf("Child Process writes in pipe\n");
}

//parent
else
{
read(a[0],buf,sizeof(buf));
printf("Parent Process has read %s\n",buf);
}
}

Output:
Operating Systems Lab
Program: 5(B)
AIM: Program to demonstrate IPC using Named Pipes
Problem Definition: To implement inter-process communication through Named pipes
(fifo).
Problem 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

Once a FIFO special file is created, any process can open it for reading or writing, in the same
way as an ordinary file. However, it has to be open at both ends simultaneously before you can
proceed to do any input or output operations on it.

Algorithm:

1. Create a program. In that program, Create fifo file using mkfifo.


2. open the fifo file in write mode and use fgets to accept the message from keyboard and send it.
3. Close the file and once again open it in read mode to read the messages which are sent by
second process.
4. Create another program. In that program open the fifo file in read mode to read the messages
which are sent by the first process
5. Close the file and once again open it in write mode to send the messages to the first process.
Program:

Named Pipe:

#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>
#include<stdlib.h>
#include<string.h>
int main()
{
int a[2],b[2],pid;
char str[20],buf1[20],buf2[20];
pipe(a);
pipe(b);
pid=fork();
if(pid<0)
{
exit(1);
}
//child
if(pid==0)
{
strcpy(str,"Demo of Pipes\n");
write(a[1],str,strlen(str)+1);
printf("Child Process writes in pipe\n");

read(b[0],buf2,sizeof(buf2));
printf("Child Process has read %s\n",buf2);
}
//parent
else
{
sleep(1);
read(a[0],buf1,sizeof(buf1));
printf("Parent Process has read %s\n",buf1);
//strcat(buf1," MD");
write(b[1],buf1,strlen(buf1)+1);
printf("Parent Process writes in pipe\n");
}
}
Output:
Operating Systems Lab

Program: 5(C)
AIM: Program to demonstrate IPC using message queues
Problem Definition: To implement two-process communication through Echo server
application using message queues.
Problem 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

Algorithm:

1: A new message queue with a unique key is created using msgget().


2. A process is created ( using fork() ).
3: The child process sends a message using msgsnd() and sleeps for 1 second. 4: When the child
process/client sleeps, the control is transferred to the parent process. 5: The parent process reads
the message using msgrcv() and prints what the child process has sent.
6: The server then, sends (gives response) a message using msgsnd().
7: The control is again transferred to the child process where it receives (reads) the message
using msgrcv() and prints what the parent process has sent.
8: The program terminates.
Program:

IPC Message Queue 1:

#include<stdio.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<string.h>
#include<unistd.h>
int main()
{
int pid, msgid;
char str[30],buf[30];
msgid = msgget((key_t)101,IPC_CREAT|0600);
pid = fork();
if(pid==0)
{
strcpy(str,"Message Queue demo");
msgsnd(msgid,str,sizeof(str),0);
}
else if(pid>0)
{
msgrcv(msgid,buf,sizeof(buf),0,0);
printf("message recieved: %s \n",buf);
}
else
{
perror("Error is creating msg queue");
}
}

Output:
IPC Message Queue 2:

#include<stdio.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<string.h>
#include<unistd.h>
int main()
{
int pid, msgid;
char str[30],buf1[30],buf2[30];
msgid = msgget((key_t)134,IPC_CREAT|0600);
pid = fork();
if(pid==0)
{
strcpy(str,"Message From child to parent");
msgsnd(msgid,str,sizeof(str),0);
msgrcv(msgid,buf1,sizeof(buf1),0,0);
printf("message recieved: %s \n",buf1);
}
else if(pid>0)
{
strcpy(str,"Message from parent to child");
msgrcv(msgid,buf2,sizeof(buf2),0,0);
msgsnd(msgid,str,sizeof(str),0);
printf("message recieved: %s \n",buf2);
}
else
{
perror("Error is creating msg queue");
}
}

Output:
Operating Systems Lab

Program: 5(D)
AIM: Program to demonstrate usage of Shared Memory
Problem Definition: To demonstrate basic operations with shared memory
Problem Description: 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.

Algorithm:

1: The parent process creates the shared memory. A child process is created.

2: The child process attaches to the shared memory and writes a message into it

3: The parent process reads the message from shared memory and prints it

4: The program terminates.


Program:

Shared Memory 1:
#include<stdio.h>
#include<string.h>
#include<sys/shm.h>
#include<unistd.h>
#include<sys/ipc.h>
int main()
{
int pid,shmid;
char *p1;
shmid= shmget((key_t)150,100,IPC_CREAT|0600);
p1=(char *)shmat(shmid,0,0);
pid=fork();
if(pid==0)
{
strcpy(p1,"demo of shared memory");
}
else if(pid>0)
{
printf("shared memory is %s \n",p1);
}
}

Output:
Shared Memory 2:
#include<stdio.h>
#include<string.h>
#include<sys/shm.h>
#include<unistd.h>
#include<sys/ipc.h>
int main()
{
int pid,shmid;
char *p1,*p2;
shmid= shmget((key_t)150,100,IPC_CREAT|0600);
p1=(char *)shmat(shmid,0,0);
p2=(char *)shmat(shmid,0,0);
pid=fork();
if(pid==0)
{
strcpy(p1,"demo of shared memory");
printf("shared memory from parent: %s",p2);
}
else if(pid>0)
{
printf("shared memory is %s \n",p1);
strcpy(p2,"demo of shared memory");
}
}

Output:
Operating Systems Lab
Program: 6(A)
AIM: Program to simulate solution for producer consumer problem
Problem Definition: To write a program to simulate a solution for producer consumer
problem
Problem Description: The program implements solution for the classical synchronization
problem- Producer consumer. Producer-Consumer problem is a classical example of a multi
process synchronization problem. The problem describes two processes, the producer and the
consumer, who share a common, fixed-size buffer. The producer's job is to generate a piece of
data, put it into the buffer and start again. At the same time the consumer is consuming the data
(i.e. removing it from the buffer) one piece at a time. A producer process produces information
that is consumed by a consumer process. A producer can produce one item while the consumer is
consuming another item. The producer and consumer must be synchronized, so that the
consumer does not try to consume an item that has not yet been produced. Two types of buffers
can be used. The problem is to make sure that the producer won’t try to add data into the buffer if
it’s full and that the consumer won’t try to remove data from an empty buffer.
The solution for the producer is to go to sleep if the buffer is full. The next time the
consumer remove an item from the buffer, it wakeup the producer who start to fill the buffer
again. In the same way the consumer goes to sleep if it finds the buffer to be empty. The next
time the producer puts data into the buffer, it wakeup the sleeping consumer. The solution can be
reached by means of IPC, typically using semaphores.
Semaphores are synchronization primitives. They are not used for exchanging large
amount of data, but are intended to let multiple processes synchronize their operation. A
semaphore is an integer variable with two atomic operation wait and signal.
Semaphores solve the problem of lost wakeup calls. In the solution below we use two
semaphores, full count and empty count, to solve the problem. Full count is incremented and
empty count is decremented when a new item has been put into the buffer. If the producer’s tries
to decrement empty count while its value is zero. The producer is put to sleep. The next time an
item is consumed; empty count is increment and the producer wake up. The consumer works
analogously.

Algorithm:

1. Initialize mutex=1,full=0,empty=3 and x=0.


2. Define producer function. As mutex=wait(mutex), full=signal(full);
empty=wait(empty). Produce the item. Signal mutex.
3. Define consumer function. As mutex=wait(mutex), full=wait (full);
empty=signal(empty). Consume the item. Signal mutex
4. Call producer if (mutex==1 and empty !=0) and call consumer if (mutex==1 and full !=0).
5. Stop the execution.
Program:

Producer Consumer:

#include<stdio.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/sem.h>
int mutex=1,full=0,empty=3,x=0;
main()
{
int n;
void producer();
void consumer();
int wait();
int signal();
printf("\[Link]\[Link]\[Link]\n");
while(1)
{
printf("\nEnter your choice:");
scanf("%d",&n);
switch(n)
{
case 1:if((mutex==1) && (empty!=0))
producer();
else
printf("\nBuffer is full");
break;
case 2:if((mutex==1) && (full!=0))
consumer();
else
printf("\nBuffer is empty");
break;
case 3:exit(1);
}
}
}
int wait(int s)
{
return (--s);
}
int signal(int s)
{
return (++s);
}
void producer()
{
mutex=wait(mutex);
full=signal(full);
empty=wait(empty);
x++;
printf("\nProducer produced the item %d\n",x);
mutex=signal(mutex);
}

void consumer()
{
mutex=wait(mutex);
full=wait(full);
empty=signal(empty);
printf("\nConsumer consumed the item %d\n",x);
x--;
mutex=signal(mutex);
}

Output:
Operating Systems Lab
Program: 6(B)
AIM: Program to demonstrate solution for readers writers problem using
semaphores
Problem Definition: To write a program to implement a solution for Readers-Writers
problem using semaphores
Problem Description: The program implements solution for the classical synchronization
problem- Reader-Writer using Semaphore. Semaphores can be used to restrict access to the
database under certain conditions. In this example, semaphores are used to prevent any writing
processes from changing information in the database while other processes are reading from the
database. A database is to be shared among several concurrent processes. Some of these
processes may want only to read the database, whereas others may want to update (that is, to
read and write) the database. We distinguish between these two types of processes by referring to
the former as readers and to the latter as writers. Obviously, if two readers access the shared data
simultaneously, no adverse affects will result. However, if a writer and some other thread (either
a reader or a writer) access the database simultaneously, chaos may ensue. To ensure that these
difficulties do not arise, we require that the writers have exclusive access to the shared database.
This synchronization problem is referred to as the readers-writers problem.
In the solution to the first readers-writers problem, the reader processes share the
following data structures:
semaphore mutex, wrt;
int readcount;
Mutex –locks that provide mutual exclusion (i.e. if process Pi is executing in its critical section,
then no other processes can be executing in their critical section). The semaphores mutex and wrt
are initialized to 1; readcount is initialized to 0. The semaphore wrt is common to both reader
and writer processes. The mutex semaphore is used to ensure mutual exclusion when the variable
readcount is updated. The readcount variable keeps track of how many processes are currently
reading the object. The semaphore wrt functions as a mutual exclusion semaphore for the writers.
It is also used by the first or last reader that enters or exits the critical section. It is not used by
readers who enter or exit while other readers are in their critical sections.

The code for a writer process is:


do
{
wait(wrt);
//writing is performed
signal(wrt);
}while(TRUE);

The code for a reader process is:


do
{
wait(mutex);
readcount++;
if(readcount==1)
wait (wrt);
signal(mutex);
………..
//reading is performed
………..
wait(mutex);
readcount--;
if(readcount==0)
signal(wrt);
signal(mutex);
}while(TRUE);

Note that, if a writer is in the critical section and n readers are waiting, then one reader is queued
on wrt, and n-1 readers are queued on mutex. Also observe that, when a writer executes signal
(wrt), we may resume the execution of either the waiting readers on a signal waiting writing. The
selection is made by the scheduler.

Algorithm:

1. Declare semaphore variables mutex, wrt.


2. Write the code for reader.
reader()
{
sem_wait(&mutex); // gain access to reader_count
reader_count = reader_count + 1; // increment the reader_count
if (reader_count == 1)
sem_wait(wrt); // if this is the first process to read the database, a down on wrt is executed to
//prevent access to the database by a writing process
sem_post(mutex); // allow other processes to access reader_count
read_wrt(); // read the database
sem_wait(mutex); // gain access to reader_count
reader_count = reader_count - 1; // decrement reader_count
if (reader_count == 0)
sem_post(wrt); // if there are no more processes reading from the database, allow writing process
//to access the data
sem_post(mutex); // release exclusive access to reader_count
}
3. Write the code for writer
writer()
{
// create data to enter into database (non-critical)
sem_wait(wrt); // gain access to the database
write_db(); // write information to the database
sem_post(wrt); // release exclusive access to the database
}
4. From main initialize the semaphore variables mutex=1 and wrt=1.
5. Use pthread to create 3 threads for writer process and call writer process.
6. Use pthread to create 3 threads for reader process and call reader process
7. For synchronization use pthread_join
8. Terminate the program.
Program:

Reader writer:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
#include<semaphore.h>

sem_t rwmutex,mutex;
int rc=0,data=0;

void *writer(void *arg)


{
intptr_t f;
f=((intptr_t)arg);
sem_wait(&rwmutex);
data++;
printf("Writer %d has written %d\n",f,data);
sleep(1);
sem_post(&rwmutex);
}

void *reader(void *arg)


{
intptr_t f;
f=((intptr_t)arg);
sem_wait(&mutex);
rc++;
if(rc==1)
sem_wait(&rwmutex);
sem_post(&mutex);
printf("Reader %d has read %d\n",f,data);
sleep(1);
sem_wait(&mutex);
rc--;
if(rc==0)
sem_post(&rwmutex);
sem_post(&mutex);
}

int main()
{
pthread_t wtid[5],rtid[5];
int i;
sem_init(&mutex,0,1);
sem_init(&rwmutex,0,1);
for(i=0;i<5;i++)
{
pthread_create(&wtid[i],NULL,writer,(void *)i);
pthread_create(&rtid[i],NULL,reader,(void *)i);
}
for(i=0;i<5;i++)
{
pthread_join(wtid[i],NULL);
pthread_join(rtid[i],NULL);
}
}

Output:
Operating Systems Lab
Program: 6(C)
AIM: Program to demonstrate solution for dining philosopher problem using
semaphores
Problem Definition: To write a program to implement a solution for dining philosopher
problem using semaphores and shared memory
Problem Description: 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 cannot 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 with a semaphore. A philosopher tries
to grab a chopstick by executing a wait () operation on that semaphore; she releases her
chopsticks by executing the signal() operation on the appropriate semaphores. Thus, the shared
data are semaphore chopstick[5]; where all the elements of chopstick are initialized to 1. Use an
asymmetric solution; that is, an odd philosopher picks up first her left chopstick and then her
right chopstick, whereas an even philosopher picks up her right chopstick and then her left
chopstick

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);

Although this solution guarantees that no two neighbors are eating simultaneously, it
nevertheless must be rejected because it could create a deadlock. Suppose that all five
philosophers become hungry simultaneously and each grabs her left chopstick. All the elements
of the chopstick will now be equal to 0. When each philosopher tries to grab her right chopstick
she will be delayed forever.

Alternate solution is to let a philosopher take chopsticks only if both of them (i.e on her left and
right) are available and her neighbors are not in eating state. We need to have another state called
HUNGRY to code the deadlock-free solution.

The data structure used for this i

state[5]={THINKING,HUNGRY,EATING}
state[i]=EATING iff (state[(i+4)%5] !=EATING) && (state[(i+1)%5] != EATING)

Algorithm:
1: Define number of philosophers as N=5 i.e{0,1,2,3,4}, and
state[N]={THINKING, HUNGRY,EATING}
2: Philosophers neighbors are defined as LEFT (phnum+N-1) % N and RIGHT (phnum+1) % N
3: Declare mutex and s[N] semaphore variables and initialize mutex=1 and s[i]=0 where ‘i’ is the
philosopher number.
4: Create philosopher processes by using pthread. And call philosopher() upon start of
thread.
5: From the philosopher function call take_fork(*i).
6: Wait for mutex within take_fork() and then stae that philosopher is hungry and eat if
neighbors are not eating, this can be done by calling test(phnum).
7. Within test(), make, state[i]=EATING if and only if (state[(i+4)%5] !=EATING) &&
(state[(i+1)%5] != EATING). Then signal the state s[phnum] by calling sem_post which is used
to wakeup hungry philosophers during put fork.
8. After eating call sem_post(mutex). If unable to eat wait is to be signaled by using
sem_wait()
9. After eating call put_fork() to put down the chopsticks.
10. Within put_fork(), wait for mutex by using sem_wait() and then change the state as
THINKING and then test whether the neighbors of this philosopher who are HUNGRY can wake
up and go into EATING state. The program continues and pthread_join continues to wait forever.
Program:
DINING PHILOSOPHER:
#include<stdio.h>
#include<pthread.h>
#include<semaphore.h>
#define N 5
#define THINKING 2
#define HUNGRY 1
#define EATING 0
#define LEFT (phnum+N-1)%N
#define RIGHT (phnum)%N
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("Philosopher %d takes %d fork and %d
fork\n",phnum,LEFT,RIGHT);
printf("%d is eating\n",phnum);
sem_post(&S[phnum]);
} }
void takeFork(int phnum){
sem_wait(&mutex);
state[phnum]=HUNGRY;
printf("%d is hungry\n",phnum);
test(phnum);
sem_post(&mutex);
sem_wait(&S[phnum]);
sleep(1);
}
void putFork(int phnum){
sem_wait(&mutex);
state[phnum]=THINKING;
printf("philosopher %d putting fork %d and %d\n",phnum,LEFT,RIGHT);
printf("philosopher %d is thinking\n",phnum);
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("philosopher %d is thinking\n",phil[i]);
}
for(i=0;i<N;i++){
pthread_join(tid[i],NULL); } }

Output:
Operating Systems Lab
Program: 7
AIM: Program to simulate Bankers Algorithm for Deadlock avoidance

Problem Definition: To write a program to simulate Bankers Algorithm for Deadlock


avoidance.
Problem 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.
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]
ALGORITHM:
1. Start the program.
2. Get the values of resources and processes.
3. Get the avail value.
4. After allocation find the need value.
5. Check whether it’s possible to allocate.
6. If it is possible then the system is in safe state.
7. Else system is not in safe state.
8. Stop the program.
Program:

Bankers Algorithm:

#include<stdio.h>
#include<stdlib.h>
int main(){
int
max[10][10],need[10][10],allocation[10][10],available[10],finished[10
],safeseq[10];
int pr_cnt,res_cnt,i,j,count=0,process;
system("clear");
printf("\nEnter the system state information\n");
printf("Enter the no of processes:\n");
scanf("%d",&pr_cnt);
for(i=0;i<pr_cnt;i++){
finished[i]=0;
}
printf("Enter the no of resources:\n");
scanf("%d",&res_cnt);
printf("Enter the max matrix for all the processes:\n");
for(i=0;i<pr_cnt;i++){
printf("Enter max info for process[%d]:",i+1);
for(j=0;j<res_cnt;j++){
scanf("%d",&max[i][j]);
}
}
for(i=0;i<pr_cnt;i++){
printf("Enter allocation info for process[%d]\n",i+1);
for(j=0;j<res_cnt;j++){
scanf("%d",&allocation[i][j]);
}
}
printf("Enter the available resources in the system:\n");
for(i=0;i<res_cnt;i++){
printf("\navailable[%d]=",i);
scanf("%d",&available[i]);
}
for(i=0;i<pr_cnt;i++){
for(j=0;j<res_cnt;j++){
need[i][j]=max[i][j]-allocation[i][j];
}
}
do{
printf("\nAvailable resources are: \t");
for(j=0;j<res_cnt;j++)
printf("%d",available[j]);
printf("\nmax matrix:\tallocation matrix:\n");
for(i=0;i<pr_cnt;i++){
24
for(j=0;j<res_cnt;j++){
printf("%d",max[i][j]);
}
printf("\t");
for(j=0;j<res_cnt;j++){
printf("%d",allocation[i][j]);
}
printf("\n");
}
process=-1;
for(i=0;i<pr_cnt;i++){
if(finished[i]==0){
process=i;
for(j=0;j<res_cnt;j++){
if(available[j]<need[i][j]){
process=-1;
break;
}}}
if(process!=-1)
break;
}
if(process!=-1){
safeseq[count]=process+1;
count++;
for(j=0;j<res_cnt;j++){
available[j]+=allocation[process][j];
allocation[process][j]=0;
max[process][j]=0;
finished[process]=1;
}
}
}while(count!=pr_cnt && process!=-1);
if(count==pr_cnt){
printf("\nthe system is in a safe state\n");
printf("\nSafe sequence:<");
for(i=0;i<pr_cnt;i++)
printf("%d",safeseq[i]);
printf(">\n");
}
else{
printf("\nthe system is in unsafe state!!\n");
}
}
Output:
Operating Systems Lab

Program: 8(A)
AIM: Program to simulate First In First Out Page Replacement Algorithm

Problem Definition: To write a program to implement FIFO Page Replacement Algorithm.


Problem 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.
The simplest page replacement algorithm is FIFO algorithm. 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 can create a FIFO queue to hold all pages
in memory. 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. The FIFO page replacement algorithm is easy to understand
and program. However, its performance is not always good. The page replaced may be an
initialization module that was used a long time ago and is no longer needed.

Algorithm:

1. Start the program


2. Read the number of frames
3. Read the number of pages
4. Read the page numbers
5. Initialize the values in frames to -1
6. Allocate the pages in to frames in First in first out order.
7. Display the number of page faults, miss ratio and hit ratio.
8. Stop the program.
Program:

FIFO page replacement:

#include<stdio.h>

main()
{
int i,j,n,a[50],frame[10],no,k,avail,count=0;

printf("Enter the length of ref string : ");


scanf("%d",&n);

printf("Enter reference string : \n");


for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}

printf("Enter frame size : ");


scanf("%d",&no);

for(i=0;i<no;i++)
frame[i]=-1;
j=0;
printf("\nref_str\tpageframe\n");

for(i=1;i<=n;i++)
{
printf("%d\t",a[i]);
avail=0;
for(k=0;k<no;k++)
{
if(frame[k]==a[i])
avail=1;
}
if(avail==0)
{
frame[j]=a[i];
27
j=(j+1)%no;
count++;
for(k=0;k<no;k++)
printf("%d\t",frame[k]);
}
printf("\n");
}
printf("[Link] page faults = %d\n",count);
}
Output:
Operating Systems Lab
Program: 8(B)
AIM: Program to simulate Least Recently Used Page Replacement Algorithm

Problem Definition: To write a program to implement LRU Page Replacement Algorithm.


Problem 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.
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.

Algorithm:

1. Start the program


2. Read the number of frames
3. Read the number of pages
4. Read the page numbers
5. Initialize the values in frames to -1
6. Allocate the pages in to frames by selecting the page that has not been used for the longest
period of time.
7. Display the number of page faults, miss ratio and hit ratio.
8. Stop the program.
Program:

LRU page replacement:

#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 length of reference string : ");


scanf("%d",&n);
printf("Enter reference string : \n");
for(i=0;i<n;i++)
{
scanf("%d",&rs[i]);
flag[i]=0;
}
printf("Enter the frame size :");
scanf("%d",&f);
for(i=0;i<f;i++)
{
count[i]=0;
m[i]=-1;
}
printf("\nThe LRU page replcement 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)
30

{
if(i<f){
m[i]=rs[i];
count[i]=next;
next++;
}
else{
min=0;
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 = %d",pf);
printf("\n");}
printf("[Link] page faults = %d\n",pf);
}

Output:
Operating Systems Lab

Program: 9(A)
AIM: Program to simulate implementation of FCFS disk scheduling
algorithm
Problem Definition: To write a program to simulate implementation of FCFS disk
scheduling algorithm
Problem 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.

Algorithm:

1. Let Request array represents an array storing indexes of tracks that have been requested in
order of their time of arrival. ‘head’ is the position of disk head.

2. Take the tracks in order of their arrival and calculate the absolute distance of the track from
the head.

3. Increment the total seek count with this distance.

4. Currently serviced track position now becomes the new head position.

5. Go to step 2 until all tracks in request array have not been serviced.

6. Display the total seek time and average.

7. Close .
Program:

FCFS Disk Scheduling:

#include<stdio.h>
#include<stdlib.h>
int main()
{
int req[10],n,hdpos,tseek=0,i;
float avg;
printf("Enter the number of requests:");
scanf("%d",&n);
for(i=1;i<=n;i++)
{
printf("\nEnter the disk read request number %d:\t",i);
scanf("%d",&req[i]);
}
printf("\nEnter the head position:\t");
scanf("%d",&hdpos);

printf("\nThe FCFS Disk Scheduling Sequence is:\n");


for(i=1;i<=n;i++)
{
printf("%d\t",req[i]);
tseek=tseek+abs(req[i]-hdpos);
hdpos=req[i];
}
avg=(float)(tseek/n);
printf("\nTotal seek time= %d\nAverage seek
time=%f\n",tseek,avg);
}

Output:
Operating Systems Lab
Program: 9(B)
AIM: Program to simulate implementation of SSTF disk scheduling algorithm

Problem Definition: To write a program to simulate implementation of SSTF disk


scheduling algorithm
Problem 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.

Algorithm:

1. Let Request array represents an array storing indexes of tracks that have been requested.
‘head’ is the position of disk head.

2. Find the positive distance of all tracks in the request array from head.

3. Find a track from requested array which has not been accessed/serviced yet and has minimum
distance from head.

4. Increment the total seek count with this distance.

5. Currently serviced track position now becomes the new head position.

6. Go to step 2 until all tracks in request array have not been serviced.

7. Display the total seek time and average.

8. Close.
Program:

SSTF disk scheduling algorithm:

#include<stdio.h>
#include<math.h>
main()
{
int diskreq[20],temp[20],n,diskhdpos;
int i,totseek=0,min,diff,index,cnt, tpos;
float avgdiskmove;
printf ("Enter the number of disk read requests\n");
scanf("%d",&n);

printf ("Enter the [%d] disk read request positions \n",n);


for(i=0;i<n;i++)
{ scanf("%d",&diskreq[i]);
temp[i] = diskreq[i];
}

printf("Enter the initial disk head position\n");


scanf("%d",&diskhdpos);
cnt = 0; // keeps track of completion of disk requests
tpos = diskhdpos; // tpos used to keep track of the current disk
head pos

while(cnt < n){min = 999999; //find the next disk causes least disk
head movement
for(i=0;i<n;i++)
if (temp[i] != -1)
{ diff = abs(diskreq[i] - tpos);
if (min > diff){
min = diff;
index = i; //point to the next disk read request to service
}
}
totseek+= min;
temp[index] = -1; // temp array is used to keep track of
completed requests.
printf("Disk head movement from %d to %d is [%d]
\n",tpos,diskreq[index],min);
cnt++;
tpos = diskreq[index];
if (cnt == n)
break;
}
avgdiskmove = (float ) totseek/n;
printf("Total seek time to process the above [%d] disk read requests
is %d\n",n,totseek);

printf("Average seek time to process the above disk read requests is


%f\n",avgdiskmove); }
Output:

You might also like