OS Lab Manual-1
OS Lab Manual-1
MEERUT
Department of Computer Science & Engineering
Operating System Lab
List of Practical
1. Implement following sorting algorithms
a) Insertion Sort
b) Bubble Sort
c) Selection Sort
2. Simulation of following CPU scheduling algorithm.
a) First Come First Serve (FCFS)
b) Shortest Job First (SJF)
3. Simulation of following CPU scheduling algorithm.
c) Priority Scheduling
d) Round Robin Scheduling
4. Execute various UNIX system calls for
a) Process management
b) File management
c) Input/output Systems calls
5. Implementation of Banker’s algorithm
6. Implement the solution for Bounded Buffer (producer-consumer) problem using inter process
communication.
7. Implement the solutions for Readers-Writers problem using inter-process communication
technique -Semaphore.
8. Implement the solution for the dinning philosophers problem for inter process communication.
9. Implementation of contiguous allocation techniques:
a) Worst-Fit
b) Best- Fit
c) First- Fit
10. Implement file storage allocation technique:
d) Contiguous(using array)
e) Linked –list(using linked-list)
f) Indirect allocation (indexing)
Practical 1
for(i=0;i<m;i++)
{
for(j=0;j<m;j++)
{
if(b[i]<b[j])
{
t=b[j];
b[j]=b[i];
b[i]=t;
}
}
}
for(i=0;i<m;i++)
printf("%d ",b[i]);
}
for(i=0;i<m;i++)
printf("%d ",b[i]);
}
Output:
Practical 2
Program:
(A) FCFS
#include<stdio.h>
int main()
{
int n,bt[20],wt[20],tat[20],avwt=0,avtat=0,i,j;
printf("Enter total number of processes(maximum 20):");
scanf("%d",&n);
printf("\nEnter Process Burst Time\n");
for(i=0;i<n;i++)
{
printf("P[%d]:",i+1);
scanf("%d",&bt[i]);
}
wt[0]=0;
for(i=1;i<n;i++)
{
wt[i]=0;
for(j=0;j<i;j++)
wt[i]+=bt[j];
}
for(i=0;i<n;i++)
{
tat[i]=bt[i]+wt[i];
avwt+=wt[i];
avtat+=tat[i];
printf("\nP[%d]\t\t%d\t\t%d\t\t%d",i+1,bt[i],wt[i],tat[i]);
}
avwt/=i;
avtat/=i;
printf("\n\nAverage Waiting Time:%d",avwt); printf("\
nAverage Turnaround Time:%d",avtat);
return 0;
}
Output:
(B) SJF
#include<stdio.h>
int main()
{
int bt[20],p[20],wt[20],tat[20],i,j,n,total=0,pos,temp;
float avg_wt,avg_tat;
printf("Enter number of process:");
scanf("%d",&n);
temp=bt[i];
bt[i]=bt[pos];
bt[pos]=temp;
temp=p[i];
p[i]=p[pos];
p[pos]=temp;
}
wt[0]=0;
for(i=1;i<n;i++)
{
wt[i]=0;
for(j=0;j<i;j++)
wt[i]+=bt[j];
total+=wt[i];
}
avg_wt=(float)total/n;
total=0;
avg_tat=(float)total/n;
printf("nnAverage Waiting Time=%f",avg_wt);
printf("nAverage Turnaround Time=%fn",avg_tat);
}
Output:
Practical 3
a) Priority Scheduling
b) Round Robin Scheduling
Description:
Priority Scheduling
Priority scheduling is one of the most common scheduling algorithms in batch systems. Each
process is assigned a priority. Process with the highest priority is to be executed first and so
on.
Processes with the same priority are executed on first come first served basis. Priority can
be decided based on memory requirements, time requirements or any other resource
requirement.
Round robin scheduling
Round Robin is a CPU scheduling algorithm where each process is assigned a fixed time slot
in a cyclic way.
It is simple, easy to implement, and starvation-free as all processes get fair share
of CPU.
One of the most commonly used technique in CPU scheduling as a core.
It is preemptive as processes are assigned CPU only for a fixed slice of time at most.
The disadvantage of it is more overhead of context switching.
Program:
Output:
Enter the process burst no and priority
1 15 2
2 5 1
3 10 3
pnobtimepriority wtimettime
2 5 105
1 152 5 20
3 10 3 20 30
The average waiting time is :8.333333
The average turn around time is:18.333334
(b) Round robin scheduling
struct roundRobin
{
int pburst,pburst1,wtime,endtime,arrivt,boolean,flagcntl;
char pname[5];
}a[5];
int n,tq;
void input();
void initialize();
void calculate();
void display_waittime();
int main()
{
input();
initialize();
calculate();
display_waittime();
//getch();
//return 0;
}
void input()
{ inti;
printf("Enter Total no. of processes\n");
scanf("%d",&n);
for(i=0;i<n;i++)
{
printf("Enter process name:");
scanf("%s",&a[i].pname);
printf("Enter process burst time:");
scanf("%d",&a[i].pburst);
printf("Enter process arrival time:");
scanf("%d",&a[i].arrivt);
}
printf("\nEnter the time quantum/Time Slice:");
scanf("%d",&tq);
}
void initialize()
{ inti;
for(i=0;i<n;i++)
{
a[i].pburst1=a[i].pburst;
a[i].wtime=0;
a[i].endtime=0;
a[i].boolean=0;
a[i].flagcntl=0;
}
}
void calculate()
{ inti,j=0,k=0,flag=1,count=0;
printf("\n---GANTT CHART---\n");
printf("0 | ");
while(flag)
{
for(i=0;i<n;i++)
{
if((k<n)&&(a[i].arrivt<=count)&&(a[i].flagcntl==0)) //calculating waiting time for
first time
{
a[i].wtime=count-a[i].arrivt;
a[i].endtime=count;
a[i].boolean=1;
a[i].flagcntl=1;
k++;
}
if((a[i].pburst1>tq)&&(a[i].arrivt<=count))
{
if(a[i].boolean==1)
a[i].boolean=0;
else
a[i].wtime=a[i].wtime+(count-a[i].endtime);
count=count+tq;
a[i].pburst1=a[i].pburst1-tq;
a[i].endtime=count;
printf("%d %s| ",count,a[i].pname);
}
else if((a[i].pburst1>0) && (a[i].pburst1<=tq) && (a[i].arrivt<=count))
{
if(a[i].boolean==1)
a[i].boolean=0;
else
a[i].wtime=a[i].wtime+(count-a[i].endtime);
count=count+a[i].pburst1;
a[i].endtime=count;
printf("%d %s| ",count,a[i].pname);
a[i].pburst1=0;
j++;
}
else if(j==n) flag=0;
}
}
}
void display_waittime()
{ inti,tot=0,turn=0;
for(i=0;i<n;i++)
{
printf("\n\nWaiting time for Process %s is %d",a[i].pname,a[i].wtime);
tot=tot+a[i].wtime;
turn=turn+a[i].endtime-a[i].arrivt;
}
printf("\n\n\tAverage waiting time=%f",(float)tot/(float)n);
printf("\n\tAverage turnaround time=%f\n",(float)turn/(float)n);
}
Output:
a) Process Management
b) File Management
c) Input/Output System call
Fork System Call:Fork system call is used for creating a new process, which is called child
process, which runs concurrently with the process that makes the fork() call (parent process). After
a new child process is created, both processes will execute the next instruction following the fork()
system call. A child process uses the same pc(program counter), same CPU registers, same open
files which use in the parent process.
It takes no parameters and returns an integer value. Below are different values returned by fork().
#include <stdio.h>
#include <unistd.h>
int main()
{
printf("Hello world!\n");
return 0;
}
Output:
Hello world!
Hello world!
Example Program 2:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
void forkexample()
{
// child process because return value zero
if (fork() == 0)
printf("Hello from Child!\n");
Output: In the above code, a child process is created. fork() returns 0 in the child process and positive
integer in the parent process.
Here, two outputs are possible because the parent process and child process are running concurrently. So
we don’t know whether the OS will first give control to the parent process or the child process.
Example Program 3:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
void forkexample()
{
int x = 1;
if (fork() == 0)
printf("Child has x = %d\n", ++x);
else
printf("Parent has x = %d\n", --x);
}
int main()
{
forkexample();
return 0;
}
Output:Here, global variable change in one process does not affected two other processes because
data/state of two processes are different. And also parent and child run simultaneously so two outputs
are possible.
Parent has x = 0
Child has x = 2
(or)
Child has x = 2
Parent has x = 0
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
void main ()
{
int pid;
printf ("I'm the original process with Process id: %d and my parent id is: %d.\n",
getpid (), getppid ());
pid = fork (); /* Duplicate. Child and parent continue from here */
if (pid != 0) /* pid is non-zero, so I must be the parent */
{
printf ("I'm the parent process with process id %d and my parent id is %d.\n",
getpid (), getppid ());
printf ("My child's process id is %d\n", pid);
}
else /* pid is zero, so I must be the child */
{
printf ("I'm the child process with process id %d and my parent id is %d.\n",
getpid (), getppid ());
}
printf("Process with process id %d terminates.\n",getpid ());/*Both procs execute this */
}
Output:
I'm the original process with Process id: 3514 and my parent id is: 1923.
I'm the parent process with process id 3514 and my parent id is 1923.
My child's process id is 3515
Process with process id 3514 terminates.
I'm the child process with process id 3515 and my parent id is 3514.
Process with process id 3515 terminates.
Orphan Process:A process whose parent process no more exists i.e. either finished or terminated
without waiting for its child process to terminate is called an orphan process. In the following code,
parent finishes execution and exits while the child process is still executing and is called an orphan
process now. However, the orphan process is soon adopted by init process, once its parent process
dies.
Note: Insert some code, e.g., a sleep() command into the child to ensure that parent finished first
Program:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
void main ()
{
int pid;
printf ("I'm the original process with Process id: %d and my parent id is: %d.\n",
getpid (), getppid ());
pid = fork (); /* Duplicate. Child and parent continue from here */
if (pid != 0) /* pid is non-zero, so I must be the parent */
{
printf ("I'm the parent process with process id %d and my parent id is %d.\n",
getpid (), getppid ());
printf ("My child's process id is %d\n", pid);
}
else /* pid is zero, so I must be the child */
{
sleep(1);
printf ("I'm the child process with process id %d and my parent id is %d.\n",
getpid (), getppid ());
}
printf("Process with process id %d terminates.\n",getpid ());/*Both procs execute this */
}
Output:
I'm the original process with Process id: 3608 and my parent id is: 1923.
I'm the parent process with process id 3608 and my parent id is 1923.
My child's process id is 3609
Process with process id 3608 terminates.
sanjiv@sanjiv-HP-Notebook:~$ I'm the child process with process id 3609 and my parent id is
2087.
Process with process id 3609 terminates.
Program:
#include<stdio.h>
#include<sys/wait.h>
#include<unistd.h>
int main()
{
int pid = fork ();
printf("Process id of the child process is: %d\n",pid);
if (pid== 0) {
printf("Child Process is going to sleep \n");
sleep(30);
exit(1);
printf("Child process is awaken now \n");
}
else
{
printf("HP: hello from parent process\n");
printf("Parent is waitng for termination of child process\n");
wait(NULL);
printf("Now child process has terminated\n");
}
printf("Bye\n");
return 0;
}
Output:
Process id of the child process is: 5906
HP: hello from parent process
Parent is waitng for termination of child process
Process id of the child process is: 0
Child Process is going to sleep
Now child process has terminated
Bye
Description: File Management
The file structure related system calls available in the UNIX system let you 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 that identifies the I/O channel.
A channel is a connection between a process and a file that appears to the process as an unformatted
stream of bytes. The kernel presents and accepts data from the channel as a process reads and
writes thatchannel. To a process then, all input and output operations are synchronous and
unbuffered.
When doing I/O, a process specifies the file descriptor for an I/Ochannel, a buffer to be filled or
emptied, and the maximum size of data to be transferred. An I/O channel may allow input, output,
or both. Furthermore, each channel has a read/write pointer. Each I/O operation starts where the
last operation finished and advances the pointer by thenumber of bytes transferred. A process can
access a channel's data randomly by changing the read/write pointer.
All input and output operations start by opening a file using either the "creat()" or "open()" system
calls. These calls return a file descriptor that identifies the I/O channel. Recall that file descriptors
0, 1, and 2 refer to standard input, standard output, and standard error files respectively, and that file
descriptor 0 is a channel to your terminal's keyboard and file descriptors 1 and 2 arechannels to your
terminal's display screen.
Creat() System Call: The prototype for the creat() system call is:
where file_name is pointer to a null terminated character string that names the file and mode defines
the file's access permissions. The mode is usually specified as an octal number such as 0666 that
would mean read/write permission for owner, group, and others or the mode may also be entered
using manifest constants defined in the "/usr/include/sys/stat.h" file. If the file named by file_name
does not exist, the UNIX system creates it with the specified mode permissions. However, if the file
does exist, its contents are discarded and the mode value is ignored. The permissions of the existing
file are retained.
Program:
#include <stdio.h>
#include <sys/stat.h> /* defines S_IREAD & S_IWRITE */
#include<unistd.h>
#include <fcntl.h> /* open(), creat() - and fcntl() */
#include <stdlib.h>
int main()
{
int fd;
fd = creat("datafile.dat", S_IREAD |
S_IWRITE); if (fd == -1)
printf("Error in opening datafile.dat\n");
else
{
printf("datafile.dat opened for read/write access\n");
printf("datafile.dat is currently empty\n");
}
close(fd);
exit (0);
}
Output:
datafile.dat opened for read/write access
datafile.dat is currently empty
The following is a sample of the manifest constants for the mode argument as defined in
/usr/include/sys/stat.h:
Multiple mode values may be combined by or'ing (using the | operator) the values together as
demonstrated in the above sample program.
open() System Call: open() lets you open a file for reading, writing, or reading and writing.
where file_name is a pointer to the character string that names the file, option_flags represent
the type of channel, and mode defines the file's access permissions if the file is being created.
Program:
#include <stdio.h>
#include <sys/stat.h> /* defines S_IREAD & S_IWRITE */
#include<unistd.h>
#include <fcntl.h> /* open(), creat() - and fcntl() */
#include <stdlib.h>
int main()
{
int fd;
char buffer[80];
close() System Call: To close a channel, use the close() system call. The prototype for the close()
system call is:
int close(file_descriptor)
int file_descriptor;
where file_descriptor identifies a currently open channel. Close() fails if file_descriptor does
not identify a currently open channel.
Read() and write() System Call: The read() system call does all input and the write() system call
does all output. When used together, they provide all the tools necessary to do input and output
sequentially. When used with the lseek() system call, they provide all the tools necessary to do
input and output randomly.
Both read() and write() take three arguments. Their prototypes are:
where file_descriptor identifies the I/O channel, buffer_pointer points to the area in memory where
the data is stored for a read() or where the data is taken for a write(), and transfer_size defines the
maximum number of characters transferred between the file and the buffer. read() and write()
return the number of bytes transferred.
There is no limit on transfer_size, but you must make sure it's safe to copy transfer_size bytes to or
from the memory pointed to bybuffer_pointer. A transfer_size of 1 is used to transfer a byte at
atime for so-called "unbuffered" input/output. The most efficient value for transfer_size is the size
of the largest physical record the I/O channel is likely to have to handle. Therefore, 1K bytes -- the
disk block size -- is the most efficient general-purpose buffer size for a standard file. However, if
you are writing to a terminal, the transfer is best handled in lines ending with a newline.
Program:
#include <stdio.h>
#include <sys/stat.h> /* defines S_IREAD & S_IWRITE */
#include<unistd.h>
#include <fcntl.h> /* open(), creat() - and fcntl() */
#include <stdlib.h>
int main()
{
int fd;
char buffer[80];
lseek() System Call:The UNIX system file system treats an ordinary file as a sequence of bytes.
No internal structure is imposed on a file by the operating system. Generally, a file is read or
written sequentially -- that is, from beginning to the end of the file. Sometimes sequential reading
and writing is not appropriate. It may be inefficient, for instance, to read an entire file just to move
to the end of the file to add characters. Fortunately, the UNIX system lets you read and write
anywhere in the file. Known as "random access", this capability is made possible with the lseek()
system call. During file I/O, the UNIX system uses a long integer, also called a File Pointer, to
keep track of the next byte to read or write. This long integer represents the number of bytes from
the beginning of the file to that next character. Random access I/O is achieved by changing the
value of this file pointer using the lseek() system call.
The prototype for lseek() is:
where file_descriptor identifies the I/O channel and offset and whence work together to describe
how to change the file pointer according to the following table:
If successful, lseek() returns a long integer that defines the new file pointer value measured in bytes
from the beginning of the file. If unsuccessful, the file position does not change. Certain devices
are incapable of seeking, namely terminals and the character interface to a tape drive. lseek() does
not change the file pointer to these devices.
Program:
#include <stdio.h>
#include <sys/stat.h> /* defines S_IREAD & S_IWRITE */
#include<unistd.h>
#include <fcntl.h> /* open(), creat() - and fcntl() */
#include <stdlib.h>
int main()
{
int fd;
long position;
fd = open("datafile.dat", O_RDONLY);
if ( fd != -1)
{
position = lseek(fd, 0L, 2); /* seek 0 bytes from end-of-file */
if (position != -1)
printf("The length of datafile.dat is %ld bytes.\n", position);
else
perror("lseek error");
}
else
printf("can't open datafile.dat\n");
close(fd);
}
Description: The banker‟s algorithm is a resource allocation and deadlock avoidance algorithm
that tests for safety by simulating the allocation for predetermined maximum possible amounts of
all resources, then makes an “s-state” check to test for possible activities, before deciding
whether allocation should be allowed to continue.
Following Data structures are used to implement the Banker‟s Algorithm:
Let ‘n’ be the number of processes in the system and ‘m’ be the number of resources types.
Available:
It is a 1-d array of size ‘m’ indicating the number of available resources of each type.
Available[ j ] = k means there are ‘k’ instances of resource type Rj
Max:
It is a 2-d array of size „n*m’ that defines the maximum demand of each process in
a system.
Max[ i, j ] = k means process Pi may request at most ‘k’ instances of resource type Rj.
Allocation:
It is a 2-d array of size ‘n*m’ that defines the number of resources of each type currently
allocated to each process.
Allocation[ i, j ] = k means process Pi is currently allocated ‘k’ instances of resource
type Rj
Need:
It is a 2-d array of size ‘n*m’ that indicates the remaining resource need of each process.
Need [ i, j ] = k means process Pi currently need ‘k’ instances of resource type Rj
for its execution.
Need [ i, j ] = Max [ i, j ] – Allocation [ i, j ]
Allocationi specifies the resources currently allocated to process Pi and Needi specifies the
additional resources that process Pi may still request to complete its task.
Banker‟s algorithm consists of Safety algorithm and Resource request algorithm
Safety Algorithm
The algorithm for finding out whether or not a system is in a safe state can be described as
follows:
1) Let Work and Finish be vectors of length „m‟ and „n‟
respectively. Initialize: Work = Available
Finish[i] = false; for i=1, 2, 3, 4….n
2) Find an i such that both
a) Finish[i] = false
b) Needi <= Work
if no such i exists goto step (4)
3) Work = Work + Allocation[i]
Finish[i] = true
goto step (2)
4) if Finish [i] = true for all i
then the system is in a safe state
Resource-Request Algorithm
Let Requesti be the request array for process Pi. Requesti [j] = k means process Pi wants k
instances of resource type Rj. When a request for resources is made by process Pi, the following
actions are taken:
1) If Requesti <= Needi
Goto step (2) ; otherwise, raise an error condition, since the process has exceeded its maximum
claim.
2) If Requesti <= Available
Goto step (3); otherwise, Pi must wait, since the resources are not available.
3) Have the system pretend to have allocated the requested resources to process Pi by modifying
the state as
follows:
Available = Available – Requesti
Allocationi = Allocationi + Requesti
Needi = Needi– Requesti
Example:
Considering a system with five processes P0 through P4 and three resources of type A, B, C.
Resource type A has 10 instances, B has 5 instances and type C has 7 instances. Suppose at
time t0 following snapshot of the system has been taken:
Question2. Is the system in a safe state? If Yes, then what is the safe sequence?
Applying the Safety algorithm on the given system,
Question3. What will happen if process P1 requests one additional instance of resource type
A and two instances of resource type C?
We must determine whether this new system state is safe. To do so, we again execute Safety
algorithm on the above data structures.
Hence the new system state is safe, so we can immediately grant the request for process P1 .
#include<stdio.h>
#include<iostream.h>
// Number of processes
int P = 5;
// Number of
resources int R = 3;
found = true;
}
}
}
return true;
}
// Driver code
int main()
{
int processes[] = {0, 1, 2, 3, 4};
return 0;
}
OUTPUT:
The producer‟s job is to generate 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.
Problem : 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.
Solution : The producer is to either go to sleep or discard data if the buffer is full. The next time
the consumer removes an item from the buffer, it notifies the producer, who starts to fill the
buffer again. In the same way, the consumer can go to sleep if it finds the buffer to be empty.
The next time the producer puts data into the buffer, it wakes up the sleeping consumer.
An inadequate solution could result in a deadlock where both processes are waiting to be
awakened.
In the post Producer-Consumer solution, we have discussed above solution by using inter-thread
communication(wait(), notify(), sleep()). In this post, we will use Semaphores to implement the
same.
The below solution consists of four classes:
1. Q : the queue that you‟re trying to synchronize
2. Producer : the threaded object that is producing queue entries
3. Consumer : the threaded object that is consuming queue entries
4. PC : the driver class that creates the single Q, Producer, and Consumer.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
int buf[256];
int in = 0;
int out = 0;
sem_t full;
sem_t empty;
sem_t mutex;
int buf_size;
int counter = 0;
int main()
{
int produce, consume;
int i;
printf("\nThe Buffer Size:");
scanf("%d", &buf_size);
printf("\nThe Producer:");
scanf("%d", &produce);
printf("\nThe Consumer:");
scanf("%d", &consume);
pthread_t prod, cons;
void* exit_status;
sem_init(&full, 0, 0);
sem_init(&empty, 0, buf_size);
sem_init(&mutex, 0, 1);
for (i = 0; i < produce; i++)
{
pthread_create(&prod, NULL, producer, &i);
}
for (i = 0; i < consume; i++)
{
pthread_create(&cons, NULL, consumer, &i);
}
pthread_join(prod, &exit_status);
pthread_join(cons, &exit_status);
// pthread_exit(NULL);
return 0;
}
Output:
Producer produced item : 0
Consumer consumed item : 0
Producer produced item : 1
Consumer consumed item : 1
Producer produced item : 2
Consumer consumed item : 2
Producer produced item : 3
Consumer consumed item : 3
Producer produced item : 4
Consumer consumed item : 4
Practical 7
Practical Name: Implement the solutions for Readers-Writers problem using inter-process
communication technique -Semaphore.
Description: Consider a situation where we have a file shared between many people.
If one of the people tries editing the file, no other person should be reading or writing
at the same time, otherwise changes will not be visible to him/her.
However if some person is reading the file, then others may read it at the same
time. Precisely in OS we call this situation as the readers-writers problem
Problem parameters:
One set of data is shared among a number of processes
Once a writer is ready, it performs its write. Only one writer may write at a time
If a process is writing, no other process can read it
If at least one reader is reading, no other process can write
Readers may not write and only read
Solution when Reader has the Priority over Writer
Here priority means, no reader should wait if the share is currently opened for reading.
Three variables are used: mutex, wrt, readcnt to implement solution
1. semaphore mutex, wrt; // semaphore mutex is used to ensure mutual exclusion
when readcnt is updated i.e. when any reader enters or exit from the critical section and
semaphore wrt is used by both readers and writers
2. int readcnt; // readcnt tells the number of processes performing read in the critical
section, initially 0
Functions for sempahore :
– wait() : decrements the semaphore value.
– signal() : increments the semaphore value.
Writer process:
1. Writer requests the entry to critical section.
2. If allowed i.e. wait() gives a true value, it enters and performs the write. If not allowed, it
keeps on waiting.
3. It exits the critical section.
#include<stdio.h>
#include<conio.h>
#include<stdbool.h>
struct semaphore
{
int mutex;
int rcount;
int rwait;
bool wrt;
};
void addR(struct semaphore *s)
{
if (s->mutex == 0 && s->rcount == 0)
{
printf("\nSorry, File open in Write mode.\nNew Reader added to queue.\n");
s->rwait++;
}
Else {
}
return ;
}
void remW(struct semaphore *s)
{
if(s->wrt==0) printf("\nNo Writer to Remove");
else
{
printf("\nWriter Removed\n");
s->mutex++;
s->wrt=0;
if(s->rwait!=0)
{
s- >mutex-=s->rwait;
s->rcount=s->rwait;
s->rwait=0;
printf("%d waiting Readers Added.",s->rcount);
}
}
}
int main()
{
struct semaphore S1={1,0,0};
while(1)
{
//system("cls");
printf("Options :-\n1.Add Reader.\n2.Add Writer.\n3.Remove Reader.\n4.Remove
Writer.\n5.Exit.\n\n\tChoice : ");
int ch;
scanf("%d",&ch);
switch(ch)
{
OUTPUT
File open in Write mode
New reader added to queue
Practical 8
Practical Name : Implement the solution for the dinning philosophers problem for inter process
communication.
Program:
#include<stdio.h>
#define n 4
struct fork{
int taken;
}ForkAvil[n];
struct philosp{
int left;
int right;
}Philostatus[n];
void goForDinner(int philID){ //same like threads concept here cases implemented
if(Philostatus[philID].left==10 && Philostatus[philID].right==10)
printf("Philosopher %d completed his dinner\n",philID+1);
//if already completed dinner
else if(Philostatus[philID].left==1 && Philostatus[philID].right==1){
//if just taken two forks
printf("Philosopher %d completed his dinner\n",philID+1);
Philostatus[philID].left = Philostatus[philID].right = 10; //remembering that he completed
dinner by assigning value 10
int otherFork = philID-1;
if(otherFork== -1)
otherFork=(n-1);
if(philID== -1)
philID=(n-1);
if(ForkAvil[philID].taken == 0){
ForkAvil[philID].taken = Philostatus[dupphilID].right = 1;
printf("Fork %d taken by Philosopher %d\n",philID+1,dupphilID+1);
}else{
printf("Philosopher %d is waiting for Fork %d\n",dupphilID+1,philID+1);
}
}
}
else if(Philostatus[philID].left==0){ //nothing taken
yet if(philID==(n-1)){
if(ForkAvil[philID-1].taken==0){ //KEY POINT OF THIS PROBLEM, THAT LAST
PHILOSOPHER TRYING IN reverse DIRECTION
ForkAvil[philID-1].taken = Philostatus[philID].left = 1;
printf("Fork %d taken by philosopher %d\n",philID,philID+1);
}else{
printf("Philosopher %d is waiting for fork %d\n",philID+1,philID);
}
}else{ //except last philosopher case
if(ForkAvil[philID].taken == 0){
ForkAvil[philID].taken = Philostatus[philID].left = 1;
printf("Fork %d taken by Philosopher %d\n",philID+1,philID+1);
}else{
printf("Philosopher %d is waiting for Fork %d\n",philID+1,philID+1);
}
}
}else{}
}
int main(){
for(i=0;i<n;i++)
ForkAvil[i].taken=Philostatus[i].left=Philostatus[i].right=0;
while(compltedPhilo<n){
/* Observe here carefully, while loop will run until all philosophers complete dinner
Actually problem of deadlock occur only thy try to take at same time
This for loop will say that they are trying at same time. And remaining status will
print by go for dinner function
*/
for(i=0;i<n;i++)
goForDinner(i);
printf("\nTill now num of philosophers completed dinner are %d\n\n",compltedPhilo);
}
return 0;
}
Output
Fork 1 taken by Philosopher 1
Fork 2 taken by Philosopher 2
Fork 3 taken by Philosopher 3
Philosopher 4 is waiting for fork 3
Till now num of philosophers completed dinner are 0
Fork 4 taken by Philosopher 1
Philosopher 2 is waiting for Fork 1
Philosopher 3 is waiting for Fork 2
Philosopher 4 is waiting for fork 3
Till now num of philosophers completed dinner are 0
Philosopher 1 completed his dinner
Philosopher 1 released fork 1 and fork 4
Fork 1 taken by Philosopher 2
Philosopher 3 is waiting for Fork 2
Philosopher 4 is waiting for fork 3
Till now num of philosophers completed dinner are 1
Philosopher 1 completed his dinner
Philosopher 2 completed his dinner
Philosopher 2 released fork 2 and fork 1
Fork 2 taken by Philosopher 3
Philosopher 4 is waiting for fork 3
Till now num of philosophers completed dinner are 2
Philosopher 1 completed his dinner
Philosopher 2 completed his dinner
Philosopher 3 completed his dinner
Philosopher 3 released fork 3 and fork 2
Fork 3 taken by philosopher 4
Till now num of philosophers completed dinner are 3
Philosopher 1 completed his dinner
Philosopher 2 completed his dinner
Philosopher 3 completed his dinner
Fork 4 taken by philosopher 4
Till now num of philosophers completed dinner are 3
Philosopher 1 completed his dinner
Philosopher 2 completed his dinner
Philosopher 3 completed his dinner
Philosopher 4 completed his dinner
Philosopher 4 released fork 4 and fork 3
Till now num of philosophers completed dinner are 4
Practical 9
a) Worst –fit
b) Best-fit
c) First-fit
Description: One of the simplest methods for memory allocation is to divide memory into
several fixed-sized partitions. Each partition may contain exactly one process. In this multiple-
partition method, when a partition is free, a process is selected from the input queue and is
loaded into the free partition. When the process terminates, the partition becomes available for
another process. The operating system keeps a table indicating which parts of memory are
available and which are occupied. Finally, when a process arrives and needs memory, a memory
section large enough for this process is provided. When it is time to load or swap a process into
main memory, and if there is more than one free block of memory of sufficient size, then the
operating system must decide which free block to allocate. Best-fit strategy chooses the block
that is closest in size to the request. First-fit chooses the first available block that is large
enough. Worst-fit chooses the largest available block.
#include<stdio.h>
void main( )
{ int bsize[10], psize[10], bno, pno, flags[10], allocation[10], i, j;
for(i = 0; i < 10; i++)
{
flags[i] = 0;
allocation[i] = -1;
}
printf("Enter no. of blocks: ");
scanf("%d", &bno);
printf("\nEnter size of each block: ");
for(i = 0; i < bno; i++)
scanf("%d", &bsize[i]);
printf("\nEnter no. of processes: ");
scanf("%d", &pno);
printf("\nEnter size of each process: ");
for(i = 0; i < pno; i++)
scanf("%d", &psize[i]);
for(i = 0; i < pno; i++) //allocation as per first fit
for(j = 0; j < bno; j++)
if(flags[j] == 0 && bsize[j] >= psize[i])
{
allocation[j] = i;
flags[j] = 1;
break;
}
//display allocation details
printf("\nBlock no.\tsize\t\tprocess no.\t\tsize");
for(i = 0; i < bno; i++)
{ printf("\n%d\t\t%d\t\t", i+1, bsize[i]);
if(flags[i] == 1)
printf("%d\t\t\t%d",allocation[i]+1,psize[allocation[i]]);
else
printf("Not allocated");
}}
#include<stdio.h>
void main()
{
int fragment[20],b[20],p[20],i,j,nb,np,temp,lowest=9999;
static int barray[20],parray[20];
for(i=1;i<=np;i++)
{
for(j=1;j<=nb;j++)
{
if(barray[j]!=1)
{
temp=b[j]-p[i];
if(temp>=0)
if(lowest>temp)
{
parray[i]=j;
lowest=temp;
}}}
fragment[i]=lowest;
barray[parray[i]]=1;
lowest=10000; }
printf("\nProcess_no\tProcess_size\tBlock_no\tBlock_size\tFragment");
for(i=1;i<=np && parray[i]!=0;i++)
printf("\n%d\t\t%d\t\t%d\t\t%d\t\t%d",i,p[i],parray[i],b[parray[i]],fragment[i]);
}
#include<stdio.h>
int main()
{
int fragments[10], blocks[10], files[10];
int m, n, number_of_blocks, number_of_files, temp, top = 0;
static int block_arr[10], file_arr[10];
printf("\nEnter the Total Number of Blocks:\t");
scanf("%d",&number_of_blocks);
printf("Enter the Total Number of Files:\t");
scanf("%d",&number_of_files); printf("\
nEnter the Size of the Blocks:\n"); for(m =
0; m < number_of_blocks; m++)
{
printf("Block No.[%d]:\t", m + 1);
scanf("%d", &blocks[m]);
}
printf("Enter the Size of the Files:\n");
for(m = 0; m < number_of_files; m++)
{
printf("File No.[%d]:\t", m + 1);
scanf("%d", &files[m]);
}
for(m = 0; m < number_of_files; m++)
{
for(n = 0; n < number_of_blocks; n++)
{
if(block_arr[n] != 1)
{
temp = blocks[n] - files[m];
if(temp >= 0)
{
if(top < temp)
{
file_arr[m] = n;
top = temp;
}
}
}
fragments[m] = top;
block_arr[file_arr[m]] = 1;
top = 0;
}
}
printf("\nFile Number\tFile Size\tBlock Number\tBlock Size\tFragment");
for(m = 0; m < number_of_files; m++)
{
printf("\n%d\t\t%d\t\t%d\t\t%d\t\t%d", m, files[m], file_arr[m], blocks[file_arr[m]],
fragments[m]);
}
printf("\n");
return 0;
}
Practical 10
Program Name: Implement file storage allocation technique: Contiguous(using array), Linked –
list(using linked-list), Indirect allocation (indexing)
Description: A file is a collection of data, usually stored on disk. As a logical entity, a file
enables to divide data into meaningful groups. As a physical entity, a file should be considered in
terms of its organization. The term "file organization" refers to the way in which data is stored in
a file and, consequently, the method(s) by which it can be accessed.
Output:
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
void main()
{
int f[50], p,i, st, len, j, c, k, a;
clrscr();
for(i=0;i<50;i++)
f[i]=0;
printf("Enter how many blocks already allocated: ");
scanf("%d",&p);
printf("Enter blocks already allocated:
"); for(i=0;i<p;i++)
{
scanf("%d",&a);
f[a]=1;
}
x: printf("Enter index starting block and length: ");
scanf("%d%d", &st,&len);
k=len;
if(f[st]==0)
{
for(j=st;j<(st+k);j++)
{
if(f[j]==0)
{ f[j]=
1;
printf("%d------->%d\n",j,f[j]);
}
else
{
printf("%d Block is already allocated \n",j);
k++;
}
}
}
else
printf("%d starting block is already allocated \n",st);
printf("Do you want to enter more file(Yes - 1/No - 0)");
scanf("%d", &c);
if(c==1)
goto x;
else
exit(0);
getch();
}
Output:
2 >1
4 >1
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
void main()
{
int f[50], index[50],i, n, st, len, j, c, k, ind,count=0;
clrscr();
for(i=0;i<50;i++)
f[i]=0;
x:printf("Enter the index block: ");
scanf("%d",&ind);
if(f[ind]!=1)
{
printf("Enter no of blocks needed and no of files for the index %d on the disk : \n", ind);
scanf("%d",&n);
}
else
{
printf("%d index is already allocated \n",ind);
goto x;
}
y: count=0;
for(i=0;i<n;i++)
{
scanf("%d", &index[i]);
if(f[index[i]]==0)
count++;
}
if(count==n)
{
for(j=0;j<n;j++)
f[index[j]]=1;
printf("Allocated\n");
printf("File Indexed\n");
for(k=0;k<n;k++)
printf("%d------->%d : %d\n",ind,index[k],f[index[k]]);
}
else
{
printf("File in the index is already allocated \n");
printf("Enter another file indexed");
goto y;
}
printf("Do you want to enter more file(Yes - 1/No - 0)");
scanf("%d", &c);
if(c==1)
goto x;
else
exit(0);
getch();
}
Output: