Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
59 views

Operating System Lab File

The document describes a list of 10 experiments related to operating systems. The experiments cover topics like process management, file management, memory management, scheduling algorithms, and inter-process communication. Key system calls like fork(), exec(), wait(), open(), read(), write() are discussed in the context of some of the experiments.

Uploaded by

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

Operating System Lab File

The document describes a list of 10 experiments related to operating systems. The experiments cover topics like process management, file management, memory management, scheduling algorithms, and inter-process communication. Key system calls like fork(), exec(), wait(), open(), read(), write() are discussed in the context of some of the experiments.

Uploaded by

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

List of Experiments

Minimum Ten / Eight experiments to be performed (As per syllabus)

S. Experiments
No
1 Study of hardware and software requirements of different operating systems
(UNIX,LINUX,WINDOWS XP, WINDOWS7/8
Execute various UNIX system calls for
2 i. Process management
ii. File management
iii. Input/output Systems calls
Implement CPU Scheduling Policies:
i. SJF
3 ii. Priority
iii. FCFS
iv. Multi-level Queue
Implement file storage allocation technique:
4 i. Contiguous(using array)
ii. Linked –list(using linked-list)
iii. Indirect allocation (indexing)
Implementation of contiguous allocation techniques:
i. Worst-Fit
5
ii. Best- Fit
iii. First- Fit
Calculation of external and internal fragmentation
6 i. Free space list of blocks from system
ii. List process file from the system

7 Implementation of resource allocation graph RAG)

8 Implementation of Banker‟s algorithm

9 Implement the solution for Bounded Buffer (producer-consumer) problem using inter
process communication techniques-Semaphores.
10 Implement the solutions for Readers-Writers problem using inter process
communication technique –Semaphore.
Beyond Syllabus

Implement disk scheduling algorithms:


1 (i) FCFS
(ii) SCAN
(iii) C-SCAN
Experiment 1
Objective: Study of hardware and software requirements of different operating systems (UNIX,
LINUX, WINDOWS XP, WINDOWS7/8.
Solution:
Operating System: An Operating system (OS) is software which acts as an interface between the
end user and computer hardware. Every computer must have at least one OS to run other
programs. An application likes Chrome, MS Word, Games, etc needs some environment in which
it will run and perform its task. The OS helps you to communicate with the computer without
knowing how to speak the computer's language. It is not possible for the user to use any
computer or mobile device without having an operating system.

Key Differences Between Linux vs Windows


● Linux is open source operating system whereas Windows OS is commercial.
● Linux has access to source code and alters the code as per user need whereas Windows does
not have access to source code.
● Linux will run faster than windows latest editions even with a modern desktop environment
and features of the operating system whereas windows are slow on older hardware.
● Linux distributions don’t collect user data whereas Windows collect all the user details which
lead to privacy concern.
● Linux is more reliable then windows as in Linux we can kill application if they hung through x
kill command whereas, in windows, we need to try multiple times to kill it.
● Linux supports a wide variety of free software’s than windows but windows have a large
collection of video game software.
● In Linux software cost is almost free as all programs, utilities, complex applications such as
open office are free but windows also have many free programs and utilities but most of the
programs are commercial.
● Linux is highly secure because it’s easy to identify bugs and fix whereas Windows has a large
user base and becomes a target for developers of viruses and malware.
● Linux is used by corporate organizations as servers and operating system for security purpose
at Google, Facebook, twitter etc. whereas windows are mostly used by gamers and business
users.
● Linux and windows have same priority over hardware and driver support in the present
situation.

Hardware Requirements (Minimum) of UNIX:


Your computer must have the following minimum configuration to successfully install WebLogic
Integration - Business Connect on a UNIX platform.
● Processor: Compatible x86 64-bit processor
● Random Access Memory (RAM)
o 256MB recommended
o 128MB minimum
● 250MB available hard drive space (see note)
● CD-ROM drive
● TCP/IP network interface
● A persistent Internet connection.
Note: We recommend at least a 1 GB hard drive for both the application and the documents you
exchange.

Hardware Requirements (Minimum) of Linux:


● Processor: Compatible x86 64-bit processor
● Random Access Memory (RAM)
o 256MB recommended
o 128MB minimum
● 250MB available hard drive space (see note)
● CD-ROM drive
● TCP/IP network interface
● A persistent Internet connection.
Hardware Requirements (Minimum) of Windows XP:
● Processor: Compatible x86 64-bit processor
● Random Access Memory (RAM)
o 512 MB recommended
o 128MB minimum
● 250MB available hard drive space (see note)
● CD-ROM drive
● TCP/IP network interface

Hardware Requirements (Minimum) of Windows 8/10:


● Processor: 1 gigahertz (GHz) or faster processor or System on a Chip (SoC)
● RAM: 1 gigabyte (GB) for 32-bit or 2 GB for 64-bit
● Hard drive space: 16 GB for 32-bit OS 32 GB for 64-bit OS
● Graphics card: DirectX 9 or later with WDDM 1.0 driver
● Display: 800x600
● Internet Connection: Internet connectivity is necessary to perform updates and to
download and take advantage of some features. Windows 10 Pro in S mode, Windows 10
Pro Education in S mode, Windows 10 Education in S mode and Windows 10 Enterprise
in S mode require an internet connection during the initial device setup (Out of Box
Experience or OOBE), as well as either a Microsoft account (MSA) or Azure Activity
Directory (AAD) account. Switching a device out of Windows 10 in S mode also requires
internet connectivity. Learn more about S mode here.
Experiment 2 (i)
Objective: Execute various UNIX system calls for: Process Management
Solution:
Process management uses certain system calls. They are explained below.
1. To create a new process – fork () is used.
2. To run a new program = exec () is used.
3. To make the process to wait = wait () is used.
4. To terminate the process – exit () is used.
5. To find the unique process id – getpid () is used.
6. To find the parent process id – getppid () is used.
7. To bias the currently running process property – nice () is used.

2(i).a. Example program for example of fork()

Figure: Flow of fork () system call

#include<stdio.h>
#include<unistd.h> for fork() and sleep() functions
int main()
{
int i =10;
int pid;
pid=fork();
if(pid==0)
{
for(i=0; i < 999999; i++)
{
sleep(2);
printf(" from Child process %d\n", i);
}
}
else
{
for(i=0; i < 999999; i=i+2)
{
sleep(2);
printf(" from Parent process %d\n", i);
}
}

return 0;
}
Output 2.(i).a
user@node1:~/oslab$ ./chp
from Parent process 0
from Child process 0
from Parent process 2
from Child process 1
from Parent process 4
from Child process 2
…………………..
……………………

2(i).b. Example program for example of exec()

Figure: flow of exec () system call

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int main()
{
int i =10;
char *p[]={"./hello", NULL};
int pid;

pid=fork();
if(pid==0)
{
for(i=0; i < 999999; i++)
{
sleep(2);
printf(" from Child process %d\n", i);
}
}
else
{
for(i=0; i < 999999; i=i+2)
{
sleep(2);
printf(" from parent process %d\n", i);
execv(p[0], p);
}
}

return 0;
}
Output 2.(i).b
user@node1:~/oslab$ ./chp2
from parent process 0
hello world
from Child process 0
from Child process 1
from Child process 2
from Child process 3
………
Experiment 2 (ii)
Objective: Execute various UNIX system calls for: File Management
Solution:
There are four system calls for file management,
1. open (): system call is used to know the file descriptor of user-created files. Since read and
write use file descriptor as their 1st parameter so to know the file descriptor open() system
call is used.
2. read ()system call is used to read the content from the file. It can also be used to read the
input from the keyboard by specifying the 0 as file descriptor.
3. write (): system call is used to write the content to the file.
4. close ():system call is used to close the opened file, it tells the operating system that you are
done with the file and close the file.

2(ii). Example program for file management


#include<unistd.h> // for read and write functions for input from keyboard
#include<fcntl.h> // for open function and O_CREAT and O_RDWR flags
#include<stdio.h>

int main()
{
int n,fd;
char buff[50];
printf("Enter text to write in the file:\n");
n= read(0, buff, 50);
fd=open("file",O_CREAT | O_RDWR, 0777);
write(fd, buff, n);
write(1, buff, n);
int close(int fd);
return 0;
}
Output 2.(ii)
Enter text to write in the file:
Hello world, welcome @ IncludeHelp
Hello world, welcome @ IncludeHelp
Experiment 2 (iii)
Objective: Execute various UNIX system calls for: Input / output system calls
Solution:
Standard File Descriptors: When any process starts, then that process file descriptors table’s
fd(file descriptor) 0, 1, 2 open automatically, (By default) each of these 3 fd references file table
entry for a file named /dev/tty
Read from stdin => read from fd 0: Whenever we write any character from keyboard, it read from
stdin through fd 0 and save to file named /dev/tty
Write to stdout => write to fd 1: Whenever we see any output to the video screen, it’s from the
file named /dev/tty and written to stdout in screen through fd 1

Figure: Input /output file descriptors

Basically, there are total 5 types of I/O system calls:


● Create: Used to Create a new empty file.
● open: Used to Open the file for reading, writing or both.
● close: Tells the operating system you are done with a file descriptor and Close the file which
pointed by fd.
● read: From the file indicated by the file descriptor fd, the read() function reads cnt bytes of
input into the memory area indicated by buf. A successful read() updates the access time for
the file.
● write: Writes cnt bytes from buf to the file or socket associated with fd. cnt should not be
greater than INT_MAX (defined in the limits.h header file). If cnt is zero, write() simply
returns 0 without attempting any other action.

2(iii). Example program for Input/output System Calls


main()
{
char c;
int a=1, i;
while (a != 0)
{
read(0, &a, 3);
i=a;
write(1, &i, 3);
write(1, "\n", 1);
}
}
Output 2.(iii)
tarun@node1:~/oslab$ ./io
2
2
33
33
44
44
Experiment 3 (i)
Objective: Implement CPU Scheduling Policies: SJF (Shortest Job First)
Solution:
Algorithm:
Step 1. Sort all the process according to the arrival time.
Step 2. Then select that process which has minimum arrival time and minimum Burst time.
Step 3. After completion of process make a pool of process which after till the completion of
previous process and select that process among the pool which is having minimum Burst
time.
Example: Sorting the process according to brust time. (Array sorting flowchart can be used for
logic understanding)

3(i). Example program for SJF scheduling implementation

#include<stdio.h>
struct process
{
int id;
int brust;
};
typedef struct process proc;
int main()
{
int n;
printf("enter the number of processs: ");
scanf("%d", &n);
proc p[n], temp;
int i,j;
for(i=0;i<n;i++)
{
p[i].id=i;
printf("enter the brust time of process P %d :", i);
scanf("%d", &p[i].brust);
}
for(i=0;i<n-1;i++)
{
for(j=i+1;j<n;j++)
{
if(p[j].brust < p[i].brust)
{
temp.id = p[j].id;
temp.brust = p[j].brust;
p[j].id = p[i].id;
p[j].brust = p[i].brust;
p[i].id = temp.id;
p[i].brust = temp.brust;
}
}

}
int wt=0;
int twt=0;
printf("\n scheduling information \n");
for(i=0;i<n;i++)
{
twt = twt+wt;
printf("process id: %d \t wating time: %d \n",p[i].id, wt );
wt=wt+p[i].brust;
}
printf("\n avg waiting time: %1.2f :", ((float)twt/n));
return 0;
}
Input: Program 3(i):
Process Brust Time
P0 5
P1 3
P2 6
P3 4

Output:
scheduling information
process id: 1 wating time: 0
process id: 3 wating time: 3
process id: 0 wating time: 7
process id: 2 wating time: 12
avg waiting time: 5.50 :
Experiment 3 (ii)
Objective: Implement CPU Scheduling Policies: Priority Scheduling
Solution:
Algorithm:
Step 1. First input the processes with their arrival time, burst time and priority.
Step 2. Sort the processes, according to arrival time if two process arrival times is same then
sort according process priority if two process priority are same then sort according to
process number.
Step 3. Now simply apply FCFS algorithm.

Example: Sorting the process according to priority. (Array sorting flowchart can be used for logic
understanding)

3(ii). Example program for Priority scheduling implementation

#include<stdio.h>
struct process
{
int id;
int brust;
int pr;
};
typedef struct process proc;
int main()
{
int n;
printf("enter the number of processs: ");
scanf("%d", &n);
proc p[n], temp;
int i,j;
for(i=0;i<n;i++)
{
p[i].id=i;
printf("enter the brust time of process P %d :", i);
scanf("%d", &p[i].brust);
printf("enter the priority of process P %d :", i);
scanf("%d", &p[i].pr);
}
for(i=0;i<n-1;i++)
{
for(j=i+1;j<n;j++)
{
if(p[j].pr < p[i].pr)
{
temp.id = p[j].id;
temp.brust = p[j].brust;
temp.pr = p[j].pr;
p[j].id = p[i].id;
p[j].brust = p[i].brust;
p[j].pr = p[i].pr;
p[i].id = temp.id;
p[i].brust = temp.brust;
p[i].pr = temp.pr;
}
}

}
int wt=0;
int twt=0;
printf("\n scheduling information \n");
for(i=0;i<n;i++)
{
twt = twt+wt;
printf("process id: %d priority %d \t wating time: %d \n",p[i].id,p[i].pr, wt );
wt=wt+p[i].brust;

}
printf("\n avg waiting time: %1.2f :", ((float)twt/n));
return 0;
}
Input: Program 3(ii):
Process Brust Time Priority
P0 5 3
P1 3 1
P2 6 2
P3 4 4
Output:
Scheduling information
process id: 1 priority 1 wating time: 0
process id: 2 priority 2 wating time: 3
process id: 0 priority 3 wating time: 9
process id: 3 priority 4 wating time: 14
avg waiting time: 6.50
Experiment 3 (iii)
Objective: Implement CPU Scheduling Policies: FCFS (First come first serve) Scheduling
Solution:
Algorithm:
Step 1. First input the processes with their arrival time, burst time.
Step 2. Queue them in their arrival order i.e. the process that comes first then process it first.
Example:

3(iii). Example program for FCFS scheduling implementation

#include<stdio.h>
struct process
{
int id;
int brust;
int at;
};
typedef struct process proc;
int main()
{
int n;
printf("enter the number of processs: ");
scanf("%d", &n);
proc p[n], temp;
int i,j;
for(i=0;i<n;i++)
{
p[i].id=i;
printf("enter the brust time of process P %d :", i);
scanf("%d", &p[i].brust);
printf("enter the arival time of process P %d :", i);
scanf("%d", &p[i].at);
}
for(i=0;i<n-1;i++)
{
for(j=i+1;j<n;j++)
{
if(p[j].at < p[i].at)
{
temp.id = p[j].id;
temp.brust = p[j].brust;
temp.at = p[j].at;
p[j].id = p[i].id;
p[j].brust = p[i].brust;
p[j].at = p[i].at;
p[i].id = temp.id;
p[i].brust = temp.brust;
p[i].at = temp.at;
}
}

}
int wt=0;
int twt=0;
printf("\n scheduling information \n");
for(i=0;i<n;i++)
{
twt = twt+wt;
printf("process id: %d arrival-time %d \t wating time: %d \n",p[i].id,p[i].at, wt );
wt=wt+p[i].brust;
}
printf("\n avg waiting time: %1.2f :", ((float)twt/n));

return 0;
}
Input: Program 3(iii):
Process Brust Time Arival time
P0 5 3
P1 3 1
P2 6 2
P3 4 4
Output:
Scheduling information
process id: 1 arrival-time 1 wating time: 0
process id: 2 arrival-time 2 wating time: 3
process id: 0 arrival-time 3 wating time: 9
process id: 3 arrival-time 4 wating time: 14
avg waiting time: 6.50
Experiment 3 (iv)
Objective: Implement CPU Scheduling Policies: Multi level Queue Scheduling
Solution:
Algorithm:
Let, us suppose we have three level queue such that queue 1, 2 and 3. Queue 1 for system
process, queue 2 for interactive process and queue 3 for batch process. Input process
parameters from user
Step 1. If process is system process then insert this process in queue 1.
Step 2. If process is interactive process the insert this process in queue 2.
Step 3. If process is batch process then insert this process in queue 3.
Step 4. Sort all queues using FCFS.
Step 5. Process Queue 1
Step 6. Process Queue 2
Step 7. Process Queue 3
Step 8. Repeat from step 1 for further processing.

Example:

Figure: Multilevel Queue Scheduling of Process (3 queues example)

3(iv). Example program for multilevel queue scheduling implementation

#include<stdio.h>
#include<stdlib.h>
typedef struct process
{
int num;
int arrive;
int brust;
int pt;
int f;
int cpu;
int wait;
} process;
typedef struct queue
{
process p[10];
int front;
int rear;
} queue;
void insert(queue *q,process t)
{
q->p[q->rear]=t;
q->rear++;
}
void pstack(queue *que)
{
int i,j;
for(i=0;i<3;i++)
{
printf("\n queue %d is \n",i+1);
printf("Process\tarive\tbrust\t type\t I/O\t cpu \twait\n");
for(j=0;j<que[i].rear;j++)
{
printf(" %d \t %d \t %d \t %d \t %d \t %d
\t %d\n",que[i].p[j].num,que[i].p[j].arrive,que[i].p[j].brust,que[i].p[
j].pt,que[i].p[j].f,que[i].p[j].cpu,que[i].p[j].wait);
}
}
}
void fcfs_sort(queue *que)
{
process *temp;
int i,j,k,n;
for(k=0;k<3;k++)
{
n=que[k].rear;
for(i=1;i<n;i++)
{
for(j=0;j<n-i;j++)
{
if(que[k].p[j].arrive > que[k].p[j+1].arrive)
{
temp=&que[k].p[j];
que[k].p[j]=que[k].p[j+1];
que[k].p[j+1]=*temp;
}
}
}
}
}
void pque(queue *que)
{
int c=0,cp=0;
int w=0;
int j=0,k=0,l=0,t=0,i;
process *temp;
int max=0;
for(i=0;i<3;i++)
{

max=max+que[i].rear;
}
for(i=0;i<max;i++)
{
if(que[0].p[j].arrive <= cp && j< que[0].rear)
{
que[0].p[j].cpu=c;
que[0].p[j].wait=c-que[0].p[j].arrive;
if(que[0].p[j].wait < 1)
que[0].p[j].wait=0;
c=c+que[0].p[j].brust;
j++;
cp=c;
continue;
}
else if(que[1].p[k].arrive < cp && k < que[1].rear )
{
que[1].p[k].cpu=c;
que[1].p[k].wait=c-que[1].p[k].arrive;
if(que[1].p[k].wait < 1)
que[1].p[k].wait=0;
c=c+que[1].p[k].brust;
k++;
cp=c;
continue;
}
else if(que[2].p[l].arrive < cp && l < que[2].rear)
{
que[2].p[l].cpu=c;
que[2].p[l].wait=c-que[2].p[l].arrive;
if(que[2].p[l].wait < 1)
que[2].p[l].wait=0;
c=c+que[2].p[l].brust;
l++;
}
else
c=0;
}
}
int main()
{
queue que[3];
int j;
for(j=0;j<3;j++)
{
que[j].front=-1;
que[j].rear=0;
}
process temp;
int n;
printf("enter the number of process");
scanf("%d",&n);
int i;
for(i=0;i<n;i++)
{
temp.num=i+1;
temp.cpu=0;
temp.wait=0;
printf("\n enter the ariive time of process %d =",i+1);
scanf("%d",&temp.arrive);
printf("\n enter the brust time of process %d =",i+1);
scanf("%d",&temp.brust);
printf("\n enter the type of(1-back,2-forground,3-other) process %d =",i+1);
scanf("%d",&temp.pt);
printf("\n enter the feedback of process(0-for normal,1-I/O) %d =",i+1);
scanf("%d",&temp.f);
if(temp.pt>=2 && temp.f==1)
insert(&que[temp.pt-2],temp);
else if(temp.f==0)
insert(&que[temp.pt-1],temp);
else
insert(&que[temp.pt-1],temp);
}
pstack(que);
fcfs_sort(que);
printf("\n\nafter sorting of process list is \n\n");
pstack(que);
pque(que);
printf("\n\nafter processing cpu and wait is \n\n");
pstack(que);
return 0;
}
Input: Program 3(iv):
Process Arival Time Brust Time Process_Type I/O
P1 0 2 1 0
P2 2 5 1 0
P3 1 3 1 0
P4 1 3 2 0
P5 0 4 2 0
P6 2 4 2 0
P7 1 3 3 0
P8 3 4 3 0
P9 2 6 3 0
Output:
queue 1 is
Process arive brust type I/O cpu wait
1 0 2 1 0 0 0
2 2 5 1 0 0 0
3 1 3 1 0 0 0

queue 2 is
Process arive brust type I/O cpu wait
4 1 3 2 0 0 0
5 0 4 2 0 0 0
6 2 4 2 0 0 0

queue 3 is
Process arive brust type I/O cpu wait
7 1 3 3 0 0 0
8 3 4 3 0 0 0
9 2 6 3 0 0 0

after sorting of process list is


queue 1 is
Process arive brust type I/O cpu wait
1 0 2 1 0 0 0
3 1 3 1 0 0 0
3 1 3 1 0 0 0

queue 2 is
Process arive brust type I/O cpu wait
5 0 4 2 0 0 0
5 0 4 2 0 0 0
6 2 4 2 0 0 0

queue 3 is
Process arive brust type I/O cpu wait
7 1 3 3 0 0 0
9 2 6 3 0 0 0
9 2 6 3 0 0 0

after processing cpu and wait is


queue 1 is
Process arive brust type I/O cpu wait
1 0 2 1 0 0 0
3 1 3 1 0 2 1
3 1 3 1 0 5 4

queue 2 is
Process arive brust type I/O cpu wait
5 0 4 2 0 8 8
5 0 4 2 0 12 12
6 2 4 2 0 16 14

queue 3 is
Process arive brust type I/O cpu wait
7 1 3 3 0 20 19
9 2 6 3 0 23 21
9 2 6 3 0 29 27
Experiment 4 (i)
Objective: Implement file storage allocation technique: Contiguous (using array)
Solution:
About Contiguous allocation technique:
In this scheme, each file occupies a contiguous set of blocks on the disk. For example, if a file
requires n blocks and is given a block b as the starting location, then the blocks assigned to the
file will be: b, b+1, b+2,……b+n-1. This means that given the starting block address and the length
of the file (in terms of blocks required), we can determine the blocks occupied by the file.
The directory entry for a file with contiguous allocation contains
Address of starting block
Length of the allocated portion.
The file ‘mail’ in the following figure starts from the block 19 with length = 6 blocks.
Therefore, it occupies 19, 20, 21, 22, 23, 24 blocks.

Figure: Contiguous file allocation technique

4(i). Example program for Contiguous (using array) file storage allocation technique
#include<stdio.h>
struct filep
{
int id;
int start;
int count;
};
typedef struct filep files;
int main()
{
int disk[100];
int i,j,k;
for(i=0;i<100;i++)
disk[i]=-1;
files f[3];
for(i=0;i < 3;i++)
{
f[i].id=i;
printf("enter the number of blocks for file : %d", i);
scanf("%d", &f[i].count);
}
int flag = 0;
for(i=0;i<3;i++)
{
flag=0;
for(j=0;j<100;j++)
{
if(disk[j] == -1)
{

for(k=j;k< j+f[i].count && disk[k] == -1;k++)


{
flag++;
printf("\n flag for file %d : %d\n", i, flag);
}
if(flag == f[i].count)
{
for(k=j;k< j+f[i].count;k++)
{

f[i].start = j;
disk[k]=f[i].id;
}
j=j+f[i].count;
break;
}
else
{
j=j+flag;
flag=0;
}

}
if(j==99 && flag == 0)
printf("\n disk is full \n");
}
}
printf("\n here is the disk allocation details \n");
for(i=0;i<100;i++)
printf("%d ", disk[i]);
return 0;
}

Input: Program 4(i):


Disk Size = 100 (Block (all of equal size))
File ID Block_Count
File 0 5
File 1 3
File 2 2
Output:
here is the disk allocation details
0 0 0 0 0 1 1 1 2 2 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -
1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
Experiment 4 (ii)
Objective: Implement file storage allocation technique: Linked –list (using linked-list)
Solution:
About Linked List Allocation technique:
In this scheme, each file is a linked list of disk blocks which need not be contiguous. The disk
blocks can be scattered anywhere on the disk.
The directory entry contains a pointer to the starting and the ending file block. Each block
contains a pointer to the next block occupied by the file.
The file ‘jeep’ in following image shows how the blocks are randomly distributed. The last block
(25) contains -1 indicating a null pointer and does not point to any other block.

Figure: Linked List file allocation technique


4(ii). Example program for file storage allocation technique (Linked List Allocation)

#include<stdio.h>
#include<stdlib.h>
struct file
{
int id;
int block;
struct file *next_block;
};
typedef struct file f;
int main()
{
f *file1, *temp, *temp2;
int i=1,j, count;
printf("enter the number of blocks for file : %d", i);
scanf("%d", &count);
for(j=0;j<count;j++)
{
if(j==0)
{
temp=(f*)malloc(sizeof(f));
temp->id=i;
temp->block=j;
temp->next_block=NULL;
file1=temp;
printf("%d\t", i);

}
else
{
temp=file1;
while ( temp->next_block != NULL)
temp=temp->next_block;

temp2=(f*)malloc(sizeof(f));
temp2->id=i;
temp2->block=j;
temp2->next_block=NULL;
temp->next_block = temp2;
printf("%d\t", i);

}
}
printf("\n Here is the disk allocation for file : \n");
temp=file1;
while(temp!=NULL)
{
printf("file id: %d\t block number: %d\t block address %d\n", temp->id,
temp->block,(int)temp);
temp=temp->next_block;
}
return 0;}
Input: Program 4(ii):
File ID Block_Count
File 1 5

Output:
Here is the disk allocation for file :
file id: 1 block number: 0 block address 38287408
file id: 1 block number: 1 block address 38287440
file id: 1 block number: 2 block address 38287472
file id: 1 block number: 3 block address 38287504
file id: 1 block number: 4 block address 38287536
file id: 1 block number: 5 block address 38287568
Experiment 4 (iii)
Objective: Implement file storage allocation technique: Indirect allocation (indexing)
Solution:
About Indirect allocation (indexing) technique:
In this scheme, a special block known as the Index block contains the pointers to all the blocks
occupied by a file. Each file has its own index block. The ith entry in the index block contains the
disk address of the ith file block. The directory entry contains the address of the index block as
shown in the image:

Figure: Indirect (index) file allocation technique


4(iii). Example program for file storage allocation technique (Indirect (index))

#include<stdio.h>
#include<stdlib.h>
struct file
{
int id;
int block;
struct file *next_block;
};
typedef struct file f;

int main()
{
f *files[3], *temp, *temp2;
int count, i, j, id;
for(i=0;i<3;i++)
{
printf("enter the number of blocks for file : %d", i);
scanf("%d", &count);
for(j=0;j<count;j++)
{
if(j==0)
{
temp=(f*)malloc(sizeof(f));
temp->id=i;
temp->block=j;
temp->next_block=NULL;
files[i]=temp;
printf("%d\t", i);
}
else
{
temp=files[i];
while ( temp->next_block != NULL)
temp=temp->next_block;
temp2=(f*)malloc(sizeof(f));
temp2->id=i;
temp2->block=j;
temp2->next_block=NULL;
temp->next_block = temp2;
printf("%d\t", i);
}

}
}
temp=files[id];
while(temp!=NULL)
{
printf("file id: %d\t block number: %d\t block address %d\n", temp->id,
temp->block,(int)temp);
temp=temp->next_block;
}
return 0;
}
Input: Program 4(iii):
File ID Block_Count
File 0 5
File 1 4
File 2 6

Output:
disk allocation using index as file id
file id: 0 block number: 0 block address 35997744
file id: 0 block number: 1 block address 35997776
file id: 0 block number: 2 block address 35997808
file id: 0 block number: 3 block address 35997840
file id: 0 block number: 4 block address 35997872

file id: 1 block number: 0 block address 35997904


file id: 1 block number: 1 block address 35997936
file id: 1 block number: 2 block address 35997968
file id: 1 block number: 3 block address 35998000

file id: 2 block number: 0 block address 35998032


file id: 2 block number: 1 block address 35998064
file id: 2 block number: 2 block address 35998096
file id: 2 block number: 3 block address 35998128
file id: 2 block number: 4 block address 35998160
file id: 2 block number: 5 block address 35998192
Experiment 5 (i)
Objective: Implementation of contiguous allocation techniques: Worst-Fit
Solution:
Worst Fit Allocate the process to the partition which is the largest sufficient among the freely
available partitions available in the main memory.
Algorithm
Step 1. Input the total number of blocks and their size.
Step 2. Input the total number of processes and their size.
Step 3. For each process in list
Find free block having max size and greater than process size
Allocate block to process

5(i). Example program for implementation of contiguous allocation techniques: Worst-Fit

#include<stdio.h>
#include<stdlib.h>
int disk[20];
struct blocks
{
int bid;
int size;
int index;
}block;
struct processs
{
int pid;
int size;
int flag;
struct blocks b;
int fragment;
}process;

int main()
{
int nb, np, i , j;
int disk_index=0;
printf(" Total disk size is 50 \n");
printf(" enter numebr of blocks: ");
scanf("%d", &nb);
struct blocks bls[nb], temp;

for(i=0;i<nb;i++)
{
bls[i].bid=i;
printf("enter the size of block %d ", i);
scanf("%d", &bls[i].size);
bls[i].index=disk_index;
disk_index=disk_index+bls[i].size;

}
printf(" enter numebr of process: ");
scanf("%d",&np);
struct processs ps[np];
for(i=0;i<np;i++)
{
ps[i].pid=i;
printf("enter the size of process %d ", i);
scanf("%d", &ps[i].size);
ps[i].flag=-1;

}
for(i=0;i<nb-1;i++)
{
for(j=i+1;j<nb;j++)
{
if(bls[j].size > bls[i].size)
{
temp.bid = bls[j].bid;
temp.size = bls[j].size;
temp.index = bls[j].index;

bls[j].bid = bls[i].bid;
bls[j].size = bls[i].size;
bls[j].index = bls[i].index;

bls[i].bid = temp.bid;
bls[i].size = temp.size;
bls[i].index = temp.index;
}
}

}
for(i=0;i<np;i++)
{
if(i >= nb || bls[i].size < ps[i].size)
printf("\n no block is available for the process \n");
else
ps[i].b=bls[i];
}
printf(" \n now process block allocation list is \n");
for(i=0;i<np;i++)
{
printf(" process id: %d process size %d block id %d free space %d\n", ps[i].pid,
ps[i].size, ps[i].b.bid, ps[i].b.size-ps[i].size);
}

return 0;
}

Input: Program 5(i):


Block ID Block_size
Block 0 5
Block 1 4
Block 2 8
Block 3 3

Process ID Process_size
Process 0 3
Process 1 2
Process 2 4
Output:
now process block allocation list is
process id: 0 process size 3 block id 2 free space 5
process id: 1 process size 2 block id 0 free space 3
process id: 2 process size 4 block id 1 free space 0
Experiment 5 (ii)
Objective: Implementation of contiguous allocation techniques: Best-Fit
Solution:
Best Fit Allocate the process to the partition which is the first smallest sufficient partition among
the free available partition.
Algorithm
Step 1. Input the total number of blocks and their size.
Step 2. Input the total number of processes and their size.
Step 3. For each process in list
Find free block where, block_size - process _size = minimum
Allocate block to process

5(ii). Example program for implementation of contiguous allocation techniques: Best-Fit

#include<stdio.h>
#include<stdlib.h>
int disk[20];
struct blocks
{
int bid;
int size;
int index;
}block;
struct processs
{
int pid;
int size;
int flag;
struct blocks b;
int fragment;
}process;
int main()
{
int nb, np, i , j;
int disk_index=0;
printf(" Total disk size is 20 \n");
printf(" enter numebr of blocks: ");
scanf("%d", &nb);
struct blocks bls[nb];
for(i=0;i<nb;i++)
{
bls[i].bid=i;
printf("enter the size of block %d ", i);
scanf("%d", &bls[i].size);
bls[i].index=disk_index;
disk_index=disk_index+bls[i].size;

}
printf(" enter numebr of process: ");
scanf("%d",&np);
struct processs ps[np];
for(i=0;i<np;i++)
{
ps[i].pid=i;
printf("enter the size of process %d ", i);
scanf("%d", &ps[i].size);
ps[i].flag=-1;

}
int temp,temp2=20, bindex, pindex;
for(i=0; i<nb;i++)
{
for(j=0;j<np;j++)
{
temp = bls[i].size - ps[j].size;
if(temp < 0)
{
continue;
}
else if(temp < temp2)
{
if(ps[j].flag == -1)
{
pindex=j;
temp2=temp;
}
}
}
ps[pindex].b = bls[i];
ps[pindex].flag = 1;
temp2=20;

}
printf(" \n now process block allocation list is \n");
for(i=0;i<np;i++)
{
printf(" process id: %d process size %d block id %d free space %d\n", ps[i].pid,
ps[i].size, ps[i].b.bid, ps[i].b.size-ps[i].size);
}
return 0;
}
Input: Program 5(ii):
Block ID Block_size
Block 0 5
Block 1 4
Block 2 8
Block 3 3

Process ID Process_size
Process 0 3
Process 1 2
Process 2 4
Output:
now process block allocation list is
process id: 0 process size 3 block id 1 free space 1
process id: 1 process size 2 block id 3 free space 1
process id: 2 process size 4 block id 0 free space 1
Experiment 5 (iii)
Objective: Implementation of contiguous allocation techniques: First-Fit
Solution:
First Fit: In the first fit, the partition is allocated which is first sufficient block from the top of Main
Memory.
Algorithm
Step 4. Input the total number of blocks and their size.
Step 5. Input the total number of processes and their size.
Step 6. For each process in list
Find free block where, block_size > process _size
Allocate block to process

5(iii). Example program for implementation of contiguous allocation techniques: First-Fit

#include<stdio.h>
#include<stdlib.h>
int disk[20];
struct blocks
{
int bid;
int size;
int index;
int status;
}block;
struct processs
{
int pid;
int size;
int flag;
struct blocks b;
int fragment;
}process;
int main()
{
int nb, np, i , j;
int disk_index=0;
printf(" Total disk size is 50 \n");
printf(" enter numebr of blocks: ");
scanf("%d", &nb);
struct blocks bls[nb], temp;

for(i=0;i<nb;i++)
{
bls[i].bid=i;
printf("enter the size of block %d ", i);
scanf("%d", &bls[i].size);
bls[i].index=disk_index;
disk_index=disk_index+bls[i].size;
bls[i].status = -1;

}
printf(" enter numebr of process: ");
scanf("%d",&np);
struct processs ps[np];
for(i=0;i<np;i++)
{
ps[i].pid=i;
printf("enter the size of process %d ", i);
scanf("%d", &ps[i].size);
ps[i].flag=-1;
}
for(i=0;i<np;i++)
{
for(j=0;j<nb;j++)
{
if(bls[j].size > ps[i].size && bls[j].status ==-1)
{
ps[i].b=bls[j];
bls[j].status = 1;
break;
}
}

}
printf(" \n now process block allocation list is \n");
for(i=0;i<np;i++)
{
printf(" process id: %d process size %d block id %d free space %d\n", ps[i].pid,
ps[i].size, ps[i].b.bid, ps[i].b.size-ps[i].size);
}
return 0;
}

Input: Program 5(iii):


Block ID Block_size
Block 0 5
Block 1 4
Block 2 8
Block 3 3

Process ID Process_size
Process 0 3
Process 1 2
Process 2 4
Output:
now process block allocation list is
process id: 0 process size 4 block id 0 free space 1
process id: 1 process size 2 block id 1 free space 2
process id: 2 process size 3 block id 2 free space 5
Experiment 6 (i)
Objective: Calculation of external and internal fragmentation: Free space list of blocks from
system
Solution:
External Fragmentation:
External fragmentation happens when there’s a sufficient quantity of area within the memory to
satisfy the memory request of a method. However, the process’s memory request cannot be
fulfilled because the memory offered is during a non-contiguous manner. Either you apply first-
fit or best-fit memory allocation strategy it’ll cause external fragmentation.

Figure. External Fragmentation in System


6(i). Example program for Free space list of blocks from system

#include<stdio.h>
#include<stdlib.h>
int disk[20];
struct blocks
{
int bid;
int size;
int index;
int status;
}block;
struct processs
{
int pid;
int size;
int flag;
struct blocks b;
int fragment;
}process;
int main()
{
int nb, np, i , j;
int disk_index=0;
printf(" Total disk size is 50 \n");
printf(" enter numebr of blocks: ");
scanf("%d", &nb);
struct blocks bls[nb], temp;
for(i=0;i<nb;i++)
{
bls[i].bid=i;
printf("enter the size of block %d ", i);
scanf("%d", &bls[i].size);
bls[i].index=disk_index;
disk_index=disk_index+bls[i].size;
bls[i].status = -1;

}
printf(" enter numebr of process: ");
scanf("%d",&np);
struct processs ps[np];
for(i=0;i<np;i++)
{
ps[i].pid=i;
printf("enter the size of process %d ", i);
scanf("%d", &ps[i].size);
ps[i].flag=-1;

}
for(i=0;i<np;i++)
{
for(j=0;j<nb;j++)
{
if(bls[j].size > ps[i].size && bls[j].status ==-1)
{
ps[i].b=bls[j];
bls[j].status = 1;
break;
}
}
}
printf(" \n now Free space list of blocks is \n");
int free=0;
for(i=0;i<nb;i++)
{
if(bls[i].status == -1)
{
printf(" Block id: %d Block size %d block index %d \n", bls[i].bid, bls[i].size,
bls[i].index);
free= free + bls[i].size;
}
}
printf(" \n Total external free space is: %d \n", free);
return 0;
}
Input: Program 6(i):
Disk size = 20
Block ID Block_size
Block 0 5
Block 1 4
Block 2 8
Block 3 3

Process ID Process_size
Process 0 4
Process 1 6
Process 2 2
Output:
now Free space list of blocks is
Block id: 2 Block size 3 block index 9
Total external free space is: 3
Experiment 6 (ii)
Objective: Calculation of external and internal fragmentation: List process file from the system
Solution:
Internal Fragmentation:
Internal fragmentation happens when the memory is split into mounted sized blocks. Whenever,
a method request for the memory, the mounted sized block is allotted to the method. Just in
case, the memory allotted to the method is somewhat larger than the memory requested, then
the distinction between allotted and requested memory is that the internal fragmentation.

Figure. Internal Fragmentation


6(ii). Example program for List process file from the system

#include<stdio.h>
#include<stdlib.h>
int disk[20];
struct blocks
{
int bid;
int size;
int index;
int status;
}block;
struct processs
{
int pid;
int size;
int flag;
struct blocks b;
int fragment;
}process;
int main()
{
int nb, np, i , j;
int disk_index=0;
printf(" Total disk size is 50 \n");
printf(" enter numebr of blocks: ");
scanf("%d", &nb);

struct blocks bls[nb], temp;

for(i=0;i<nb;i++)
{
bls[i].bid=i;
printf("enter the size of block %d ", i);
scanf("%d", &bls[i].size);
bls[i].index=disk_index;
disk_index=disk_index+bls[i].size;
bls[i].status = -1;

}
printf(" enter numebr of process: ");
scanf("%d",&np);
struct processs ps[np];
for(i=0;i<np;i++)
{
ps[i].pid=i;
printf("enter the size of process %d ", i);
scanf("%d", &ps[i].size);
ps[i].flag=-1;

}
for(i=0;i<np;i++)
{
for(j=0;j<nb;j++)
{
if(bls[j].size > ps[i].size && bls[j].status ==-1)
{
ps[i].b=bls[j];
bls[j].status = 1;
break;
}
}

}
printf(" \n now process block allocation list is \n");
int t_free=0;
for(i=0;i<np;i++)
{
printf(" process id: %d process size %d block id %d free space %d\n", ps[i].pid,
ps[i].size, ps[i].b.bid, ps[i].b.size-ps[i].size);
t_free = t_free + (ps[i].b.size-ps[i].size);
}
printf(" \n Total internal fragmentation space is: %d \n", t_free);
return 0;
}
Input: Program 6(ii):
Block ID Block_size
Block 0 5
Block 1 4
Block 2 8
Block 3 3

Process ID Process_size
Process 0 3
Process 1 2
Process 2 4
Output:
now process block allocation list is
process id: 0 process size 4 block id 0 free space 1
process id: 1 process size 2 block id 1 free space 2
process id: 2 process size 3 block id 2 free space 5

Total internal fragmentation space is: 8


Experiment 7
Objective: Implementation of resource allocation graph RAG)
Solution:
Resource Allocation Graph (RAG)
As Banker’s algorithm using some kind of table like allocation, request, available all that thing to
understand what is the state of the system. Similarly, if you want to understand the state of the
system instead of using those table, actually tables are very easy to represent and understand it,
but then still you could even represent the same information in the graph. That graph is called
Resource Allocation Graph (RAG).
So, resource allocation graph is explained to us what is the state of the system in terms of
processes and resources. Like how many resources are available, how many are allocated and
what is the request of each process. Everything can be represented in terms of the diagram. One
of the advantages of having a diagram is, sometimes it is possible to see a deadlock directly by
using RAG, but then you might not be able to know that by looking at the table. But the tables
are better if the system contains lots of process and resource and Graph is better if the system
contains less number of process and resource.
We know that any graph contains vertices and edges. So RAG also contains vertices and edges.
In RAG vertices are two type –
1. Process vertex – Every process will be represented as a process vertex. Generally, the process
will be represented with a circle.
2. Resource vertex – Every resource will be represented as a resource vertex.

Figure: Resource Allocation Graph


8. Example program for Implementation of resource allocation graph RAG)

#include<stdio.h>
int main()
{
int np, nr, temp, temp1;
printf("enter number of resources: ");
scanf("%d", &nr);
printf("enter number of processs: ");
scanf("%d", &np);
int rag[nr+np][nr+np];
int i, j;
for(i=0;i<np+nr;i++)
{

for(j=0; j<np+nr;j++)
{
rag[i][j]=0;
}

}
for(i=0;i<np;i++)
{
printf("enter the number of resources process %d, holding", i);
scanf("%d", &temp);
for(j=0; j<temp;j++)
{
printf("enter the ressorce number process %d holding: ", j);
scanf("%d", &temp1);
rag[np+temp1][i]=1;
}
printf("enter the number of resources process %d, requesting", i);
scanf("%d", &temp);
for(j=0; j<temp;j++)
{
printf("enter the ressorce number process %d requesting: ", i);
scanf("%d", &temp1);
rag[i][np+temp1]=1;
}
}
for(i=0;i<np+nr;i++)
{

for(j=0; j<np+nr;j++)
{
printf("%d ", rag[i][j]);
}
printf("\n ");
}
return 0;
}
Input: Program 8:

Process ID Resource Resource


Holding Requesting
Process 0 R0 R2
Process 1 R1 R0
Process 2 R2 R1
Output:
P0 P1 P2 R0 R1 R2
P0 0 0 0 0 0 1
P1 0 0 0 1 0 0
P2 0 0 0 0 1 0
R0 1 0 0 0 0 0
R1 0 1 0 0 0 0
R2 0 0 1 0 0 0
Experiment 8
Objective: Implementation of Banker‟s algorithm
Solution:
Banker’s Algorithm
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

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

9. Example program for Implementation of Banker‟s algorithm


#include <stdio.h>
int main()
{
int n, m, i, j, k;
n = 5;
m = 3;
int alloc[5][3] = { { 0, 1, 0 },
{ 2, 0, 0 },
{ 3, 0, 2 },
{ 2, 1, 1 },
{ 0, 0, 2 } };
int max[5][3] = { { 7, 5, 3 },
{ 3, 2, 2 },
{ 9, 0, 2 },
{ 2, 2, 2 },
{ 4, 3, 3 } };
int avail[3] = { 3, 3, 2 };
int f[n], ans[n], ind = 0;
for (k = 0; k < n; k++)
{
f[k] = 0;
}
int need[n][m];
for (i = 0; i < n; i++)
{
for (j = 0; j < m; j++)
need[i][j] = max[i][j] - alloc[i][j];
}
int y = 0;
for (k = 0; k < 5; k++)
{
for (i = 0; i < n; i++)
{
if (f[i] == 0)
{
int flag = 0;
for (j = 0; j < m; j++)
{
if (need[i][j] > avail[j])
{
flag = 1;
break;
}
}
if (flag == 0)
{
ans[ind++] = i;
for (y = 0; y < m; y++)
avail[y] += alloc[i][y];
f[i] = 1;
}
}
}
}
printf("Following is the SAFE Sequence\n");
for (i = 0; i < n - 1; i++)
printf(" P%d ->", ans[i]);
printf(" P%d", ans[n - 1]);

return 0;
}

Input: Program 9:
Output:
Following is the SAFE Sequence
P1 -> P3 -> P4 -> P0 -> P2
Experiment 9
Objective: Implement the solution for Bounded Buffer (producer-consumer)problem using
inter process communication techniques-Semaphores
Solution:
Producer consumer problem is a classical synchronization problem. We can solve this problem
by using semaphores.
A semaphore S is an integer variable that can be accessed only through two standard operations :
wait() and signal().
The wait() operation reduces the value of semaphore by 1 and the signal() operation increases
its value by 1.
Problem Statement – We have a buffer of fixed size. A producer can produce an item and can
place in the buffer. A consumer can pick items and can consume them. We need to ensure that
when a producer is placing an item in the buffer, then at the same time consumer should not
consume any item. In this problem, buffer is the critical section.
To solve this problem, we need two counting semaphores – Full and Empty. “Full” keeps track of
number of items in the buffer at any given time and “Empty” keeps track of number of
unoccupied slots.

11. Example program for Implement the solution for Bounded Buffer (producer-consumer)
problem using inter process communication techniques-Semaphores

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

return 0;
}

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

int signal(int s)
{
return(++s);
}

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

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

Output: Program 11

1.Producer
2.Consumer
3.Exit
Enter your choice:1

Producer produces the item 1


Enter your choice:2

Consumer consumes item 1


Enter your choice:2
Buffer is empty!!
Enter your choice:1

Producer produces the item 1


Enter your choice:1

Producer produces the item 2


Enter your choice:1

Producer produces the item 3


Enter your choice:1
Buffer is full!!
Enter your choice:3
Experiment 10
Objective: Implement the solutions for Readers-Writers problem using inter process
communication technique –Semaphore
Solution:
Readers-Writers Problem
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.

Reader process:
1. Reader requests the entry to critical section.
2. If allowed:
o it increments the count of number of readers inside the critical section. If this
reader is the first reader entering, it locks the wrt semaphore to restrict the
entry of writers if any reader is inside.
o It then, signals mutex as any other reader is allowed to enter while others are
already reading.
o After performing reading, it exits the critical section. When exiting, it checks if no
more reader is inside, it signals the semaphore “wrt” as now, writer can enter
the critical section.
3. If not allowed, it keeps on waiting.

12. Example program for Implement the solutions for Readers-Writers problem using inter
process communication technique –Semaphore
#include<stdio.h>
#include<pthread.h>
#include<semaphore.h>
sem_t mutex,writeblock;
int data = 0,rcount = 0;
void *reader(void *arg)
{
int f;
f = ((int)arg);
sem_wait(&mutex);
rcount = rcount + 1;
if(rcount==1)
sem_wait(&writeblock);
sem_post(&mutex);
printf("Data read by the reader%d is %d\n",f,data);
sleep(1);
sem_wait(&mutex);
rcount = rcount - 1;
if(rcount==0)
sem_post(&writeblock);
sem_post(&mutex);
}

void *writer(void *arg)


{
int f;
f = ((int) arg);
sem_wait(&writeblock);
data++;
printf("Data writen by the writer%d is %d\n",f,data);
sleep(1);
sem_post(&writeblock);
}
int main()
{
int i,b;
pthread_t rtid[5],wtid[5];
sem_init(&mutex,0,1);
sem_init(&writeblock,0,1);
for(i=0;i<=2;i++)
{
pthread_create(&wtid[i],NULL,writer,(void *)i);
pthread_create(&rtid[i],NULL,reader,(void *)i);
}
for(i=0;i<=2;i++)
{
pthread_join(wtid[i],NULL);
pthread_join(rtid[i],NULL);
}
return 0;
}

Output: Program 12
Data writen by the writer0 is 1
Data read by the reader0 is 1
Data read by the reader1 is 1
Data read by the reader2 is 1
Data writen by the writer1 is 2
Data writen by the writer2 is 3
Experiment 1(i)
Objective: Implement the Implement disk scheduling algorithms: FCFS
Solution:
First Come First Serve (FCFS)

FCFS is the simplest disk scheduling algorithm. As the name suggests, this algorithm entertains
requests in the order they arrive in the disk queue. The algorithm looks very fair and there is no
starvation (all requests are serviced sequentially) but generally, it does not provide the fastest
service.

Algorithm:

Step 1. Let Request array represents an array storing indexes of tracks that have been
requested in ascending order of their time of arrival. ‘head’ is the position of disk head.
Step 2. Let us one by one take the tracks in default order and calculate the absolute distance
of the track from the head.
Step 3. Increment the total seek count with this distance.
Step 4. Currently serviced track position now becomes the new head position.
Step 5. Go to step 2 until all tracks in request array have not been serviced.

Figure: chart shows the sequence in which requested tracks are serviced using FCFS.

13 (i). Example program for Implement disk scheduling algorithms: FCFS

#include<stdio.h>
int main()
{
int queue[20],n,head,i,j,k,seek=0,max,diff;
float avg;
printf("Enter the max range of disk\n");
scanf("%d",&max);
printf("Enter the size of queue request\n");
scanf("%d",&n);
printf("Enter the queue of disk positions to be read\n");
for(i=1;i<=n;i++)
scanf("%d",&queue[i]);
printf("Enter the initial head position\n");
scanf("%d",&head);
queue[0]=head;
for(j=0;j<=n-1;j++)
{
diff=abs(queue[j+1]-queue[j]);
seek+=diff;
printf("Disk head moves from %d to %d with seek
%d\n", queue[j],queue[j+1],diff);
}
printf("Total seek time is %d\n",seek);
avg=seek/(float)n;
printf("Average seek time is %f\n",avg);
return 0;
}

Output 13 (i):
Enter the max range of disk
200
Enter the size of queue request
8
Enter the queue of disk positions to be read
90 120 35 122 38 128 65 68
Enter the initial head position
50
Disk head moves from 50 to 90 with seek
Disk head moves from 90 to 120 with seek
Disk head moves from 120 to 35 with seek
Disk head moves from 35 to 122 with seek
Disk head moves from 122 to 38 with seek
Disk head moves from 38 to 128 with seek
Disk head moves from 128 to 65 with seek
Disk head moves from 65 to 68 with seek
Total seek time is 482
Average seek time is 60.250000
Experiment 1(ii)
Objective: Implement the Implement disk scheduling algorithms: SCAN
Solution:
SCAN (Elevator) algorithm
In SCAN disk scheduling algorithm, head starts from one end of the disk and moves towards the
other end, servicing requests in between one by one and reach the other end. Then the
direction of the head is reversed and the process continues as head continuously scan back and
forth to access the disk. So, this algorithm works as an elevator and hence also known as the
elevator algorithm. As a result, the requests at the midrange are serviced more and those
arriving behind the disk arm will have to wait.
Algorithm-
Step 1. Let Request array represents an array storing indexes of tracks that have been
requested in ascending order of their time of arrival. ‘head’ is the position of disk head.
Step 2. Let direction represents whether the head is moving towards left or right.
Step 3. In the direction in which head is moving service all tracks one by one.
Step 4. Calculate the absolute distance of the track from the head.
Step 5. Increment the total seek count with this distance.
Step 6. Currently serviced track position now becomes the new head position.
Step 7. Go to step 3 until we reach at one of the ends of the disk.
Step 8. If we reach at the end of the disk reverse the direction and go to step 2 until all tracks
in request array have not been serviced.
Step 9.

Figure: chart shows the sequence in which requested tracks are serviced using SCAN.

13 (ii). Example program for Implement disk scheduling algorithms: SCAN


#include<stdio.h>
int main()
{
int queue[20],n,head,i,j,k,seek=0,max,diff,temp,queue1[20],queue2[20],
temp1=0,temp2=0;
float avg;
printf("Enter the max range of disk\n");
scanf("%d",&max);
printf("Enter the initial head position\n");
scanf("%d",&head);
printf("Enter the size of queue request\n");
scanf("%d",&n);
printf("Enter the queue of disk positions to be read\n");
for(i=1;i<=n;i++)
{
scanf("%d",&temp);
if(temp>=head)
{
queue1[temp1]=temp;
temp1++;
}
else
{
queue2[temp2]=temp;
temp2++;
}
}
for(i=0;i<temp1-1;i++)
{
for(j=i+1;j<temp1;j++)
{
if(queue1[i]>queue1[j])
{
temp=queue1[i];
queue1[i]=queue1[j];
queue1[j]=temp;
}
}
}
for(i=0;i<temp2-1;i++)
{
for(j=i+1;j<temp2;j++)
{
if(queue2[i]<queue2[j])
{
temp=queue2[i];
queue2[i]=queue2[j];
queue2[j]=temp;
}
}
}
for(i=1,j=0;j<temp1;i++,j++)
queue[i]=queue1[j];
queue[i]=max;
for(i=temp1+2,j=0;j<temp2;i++,j++)
queue[i]=queue2[j];
queue[i]=0;
queue[0]=head;
for(j=0;j<=n+1;j++)
{
diff=abs(queue[j+1]-queue[j]);
seek+=diff;
printf("Disk head moves from %d to %d with seek %d\n",queue[j],queue[j+1],diff);
}
printf("Total seek time is %d\n",seek);
avg=seek/(float)n;
printf("Average seek time is %f\n",avg);
return 0;
}
Output 13 (ii):
Enter the max range of disk
200
Enter the initial head position
50
Enter the size of queue request
8
Enter the queue of disk positions to be read
90 120 35 122 38 128 65 68
Disk head moves from 50 to 65 with seek 15
Disk head moves from 65 to 68 with seek 3
Disk head moves from 68 to 90 with seek 22
Disk head moves from 90 to 120 with seek 30
Disk head moves from 120 to 122 with seek 2
Disk head moves from 122 to 128 with seek 6
Disk head moves from 128 to 200 with seek 72
Disk head moves from 200 to 38 with seek 162
Disk head moves from 38 to 35 with seek 3
Disk head moves from 35 to 0 with seek 35
Total seek time is 350
Average seek time is 43.750000
Experiment 1(iii)
Objective: Implement the Implement disk scheduling algorithms: C-SCAN
Solution:
What is C-SCAN (Circular Elevator) Disk Scheduling Algorithm?
Circular SCAN (C-SCAN) scheduling algorithm is a modified version of SCAN disk scheduling
algorithm that deals with the inefficiency of SCAN algorithm by servicing the requests more
uniformly. Like SCAN (Elevator Algorithm) C-SCAN moves the head from one end servicing all
the requests to the other end. However, as soon as the head reaches the other end, it
immediately returns to the beginning of the disk without servicing any requests on the return
trip (see chart below) and starts servicing again once reaches the beginning. This is also known
as the “Circular Elevator Algorithm” as it essentially treats the cylinders as a circular list that
wraps around from the final cylinder to the first one.

Algorithm:

Step 1. Let Request array represents an array storing indexes of tracks that have been
requested in ascending order of their time of arrival. ‘head’ is the position of disk
head.
Step 2. The head services only in the right direction from 0 to size of the disk.
Step 3. While moving in the left direction do not service any of the tracks.
Step 4. When we reach at the beginning(left end) reverse the direction.
Step 5. While moving in right direction it services all tracks one by one.
Step 6. While moving in right direction calculate the absolute distance of the track from the
head.
Step 7. Increment the total seek count with this distance.
Step 8. Currently serviced track position now becomes the new head position.
Step 9. Go to step 6 until we reach at right end of the disk.
Step 10. If we reach at the right end of the disk reverse the direction and go to step 3 until all
tracks in request array have not been serviced.

Figure: chart shows the sequence in which requested tracks are serviced using SCAN.
13 (iii). Example program for Implement disk scheduling algorithms: C-SCAN
#include<stdio.h>

int main()
{
int queue[20],n,head,i,j,k,seek=0,max,diff,temp,queue1[20],queue2[20],
temp1=0,temp2=0;
float avg;
printf("Enter the max range of disk\n");
scanf("%d",&max);
printf("Enter the initial head position\n");
scanf("%d",&head);
printf("Enter the size of queue request\n");
scanf("%d",&n);
printf("Enter the queue of disk positions to be read\n");
for(i=1;i<=n;i++)
{
scanf("%d",&temp);
if(temp>=head)
{
queue1[temp1]=temp;
temp1++;
}
else
{
queue2[temp2]=temp;
temp2++;
}
}
for(i=0;i<temp1-1;i++)
{
for(j=i+1;j<temp1;j++)
{
if(queue1[i]>queue1[j])
{
temp=queue1[i];
queue1[i]=queue1[j];
queue1[j]=temp;
}
}
}
for(i=0;i<temp2-1;i++)
{
for(j=i+1;j<temp2;j++)
{
if(queue2[i]>queue2[j])
{
temp=queue2[i];
queue2[i]=queue2[j];
queue2[j]=temp;
}
}
}
for(i=1,j=0;j<temp1;i++,j++)
queue[i]=queue1[j];
queue[i]=max;
queue[i+1]=0;
for(i=temp1+3,j=0;j<temp2;i++,j++)
queue[i]=queue2[j];
queue[0]=head;
for(j=0;j<=n+1;j++)
{
diff=abs(queue[j+1]-queue[j]);
seek+=diff;
printf("Disk head moves from %d to %d with seek %d\n",queue[j],queue[j+1],diff);
}
printf("Total seek time is %d\n",seek);
avg=seek/(float)n;
printf("Average seek time is %f\n",avg);
return 0;
}

Output 13 (iii):

Enter the max range of disk


200
Enter the initial head position
50
Enter the size of queue request
8
Enter the queue of disk positions to be read
90 120 35 122 38 128 65 68
Disk head moves from 50 to 65 with seek 15
Disk head moves from 65 to 68 with seek 3
Disk head moves from 68 to 90 with seek 22
Disk head moves from 90 to 120 with seek 30
Disk head moves from 120 to 122 with seek 2
Disk head moves from 122 to 128 with seek 6
Disk head moves from 128 to 200 with seek 72
Disk head moves from 200 to 0 with seek 200
Disk head moves from 0 to 35 with seek 35
Disk head moves from 35 to 38 with seek 3
Total seek time is 388
Average seek time is 48.500000

You might also like