You are on page 1of 38

What is Virtual Memory and how is it implemented?

We all know that a process is divided into various pages and these pages are used during the execution
of the process. The whole process is stored in the secondary memory. But to make the execution of a
process faster, we use the main memory of the system and store the process pages into it. But there is
a limitation with the main memory. We have limited space and less space in the main memory. So,
what if the size of the process is larger than the size of the main memory? Here, the concept of Virtual
Memory comes into play.

Virtual Memory is a way of using the secondary memory in such a way that it feels like we are using
the main memory.
So, the benefit of using the Virtual Memory is that if we are having some program that is larger than
the size of the main memory then instead of loading all the pages we load some important pages.

In general, when we execute a program, then the entire program is not required to be loaded fully in
the main memory. This is because only a few portions of the program are being executed at a time. For
example, the error handling part of any program is called only when there is some error and we know
that the error happens rarely. So, why to load this part of the program in the main memory and fill the
memory space? Another example can be a large-sized array. Generally, we have over-sized arrays
because we reserve the space for worst-case scenarios. But in reality, only a small part of the array is
used regularly. So, why to put the whole array in the main memory?

So, what we do is we put the frequently used pages of the program in the main memory and this will
result in fast execution of the program because whenever those pages will be needed then it will be
served from the main memory only. Other pages are still in the secondary memory. Now, if some
request to the page that is not in the main memory comes, then this situation is called a Page Miss or
Page Fault. In this situation, we remove one page from the main memory and load the desired page
from the secondary memory to the main memory at the run time i.e swapping of pages will be
performed here. By doing so, the user feels like he/she is having a lot of memory in its system but in
reality, we are just putting that part of the process in the memory that is frequently used. The
following figure shows the working in brief:
In the above image, we can see that the whole process is divided into 6 pages and out of these 6
pages, 2 pages are frequently used and due to this, these 2 pages are put into the physical memory. If
there is some request for the pages present in the physical memory, then it is directly served
otherwise if the page is not present in the physical memory then it is called a page fault and whenever
page fault occurs, then we load the demanded page in the memory and this process is known as
Demand Paging.

Demand Paging
Whenever a page fault occurs, then the process of loading the page into the memory is called demand
paging. So, in demand paging, we load the process only when we need it. Initially, when a process
comes into execution, then at that time only those pages are loaded which are required for initial
execution of the process and no other pages are loaded. But with time, when there is a need for other
pages, then the CPU will find that page from the secondary memory and load that page in the main
memory.

Following are the steps involved in demand paging:

1. The CPU first tries to find the requested page in the main memory and if it is found then it will
be provided immediately otherwise an interrupt is generated that indicates memory access
fault.
2. Now, the process is sent to the blocked/waiting state because, for the execution of the
process, we need to find the required page from the secondary memory.
3. The logical address of the process will be converted to the physical address because without
having the physical address, you can't locate the page in secondary memory.
4. Now, we apply some page replacement algorithms that can be used to swap the pages from
the main memory to secondary memory and vice-versa.
5. Finally, the page table will be updated with the removal of the address of the old page and the
addition of the address of the new page.
6. At last, the CPU provides the page to the process and the process comes to the running state
from the waiting/block state.
So, in this way, we can implement the concept of Virtual Memory with the help of Demand Paging.
What are the types of Operating Systems?

Batch Operating System


First, we will learn about the Batch Operating System. In the Batch Operating System, similar types of
jobs are grouped together into batches.
This grouping of batches is done with the help of the operator. When we have the batches ready, the
execution is done one by one for the batches which means batch-wise.
The best way to understand it is by taking an example. Let’s take an example:
Suppose that we have 100 programs to execute. Those programs are in two languages: Java and C++.
55 programs are in Java and 45 programs are in C++. Here, two batches can be created: one for all the
Java programs, and one for all the C++ programs.
Here, if we execute in batches, we will get the benefit of loading the Java compiler for 1 time only not 55
times.
Similarly for the C++, the C++ compiler will get loaded for 1 time only not 45 times.
As we are loading the compiler for the 1 time only and executing that particular batch. We have an
advantage.
This is the working model of the Batch Operating System.
Advantages:
1. It allows multiple users to use it at the same time.
2. Reduction in the time taken by the system to execute all the programs.
Disadvantages:
1. If a job fails, the other jobs will have to wait for an unknown time.
2. Batch systems are sometimes costly.
3. Difficult to debug.

Time-Sharing Operating System


Now, it's time to learn about the Time-Sharing Operating System.
Here, more than one task gets executed at a particular time with the help of the time-sharing concept.
And we have the term quantum which means the amount of time that each task gets for execution.
Quantum is the short duration of time that is decided for each task in a time-sharing operating system.
Suppose we have 4 tasks.
 Task 1
 Task 2
 Task 3
 Task 4
It starts with Task 1, it gets executed for that particular fixed amount of time.
Then, Task 2 gets the chance of execution for that particular fixed amount of time.
After that, Task 3 gets the chance of execution for that particular fixed amount of time.
And finally, Task 4 gets the chance of execution for that particular fixed amount of time.
And then again the Task 1, Task 2, Task 3, and so on. The cycle goes on.
This is the working model of the Time-Sharing Operating System.
Advantages:
1. Each task gets an equal opportunity for execution.
2. Reduction in the idle time of the CPU.
Disadvantages:
1. The data of each task should be handled properly so that they don’t get mixed during the
execution.
2. No way to give an advantage to the higher-priority task that needs immediate execution.

Distributed Operating System


In this Operating System, we have many systems and all these systems have their own CPU, main
memory, secondary memory, and resources.
As the name is distributed operating system, these systems are connected to each other over the
network.
As it is connected to each other over the network, one user can access the data of the other system. So,
remote access is the major highlight of this operating system.
And also each system can perform its task individually.
Now, let’s talk about the advantages and disadvantages of Distributed Operating Systems.
Advantages:
1. No single point of failure as we have multiple systems, if one fails, another system can execute
the task.
2. Resources are shared with each other, hence, increasing availability across the entire system.
3. It helps in the reduction of execution time.
Disadvantages:
1. Since the data is shared across the systems, it needs extra handling to manage the overall
infrastructure.
2. It is difficult to provide adequate security in distributed systems because the nodes as well as
the connections need to be secured.
3. Network failure needs to be handled.

Embedded Operating System


An embedded operating system is a specialized operating system designed to perform a specific task for a
device that is not a computer.
Examples of Embedded Operating Systems:
 The operating system of ATMs.
 The operating system in Elevators.
The operating system used in the ATMs or in the Elevators is dedicated to that specialized type of task.
Advantages:
1. It is fast as it does the specialized type of task only.
Disadvantages:
1. Only one task can be performed.

Real-time Operating System


A real-time operating system is an operating system for real-time applications that process data and
events with critically defined time constraints. It is used when we are dealing with real-time data.
Examples:
 Air Traffic Control Systems
 Medical systems
There are two types of Real-time Operating Systems:
1. Hard Real-time: When a slight delay can lead to a big problem, we use this Hard Real-time
operating system. The time constraints are very strict.
2. Soft Real-time: When a slight delay is manageable and does not impact anything as such, we use
this Soft Real-time operating system.
Advantages:
1. Maximum utilization of devices and resources.
2. These systems are almost error-free.
Disadvantages:
1. The algorithms used in Real-time Operating System is very complex.
2. Limited tasks.
3. Use Heavy System resources.
Multiprogramming vs Multiprocessing vs Multitasking

Multiprogramming
A process executing in a computer system mainly requires two things i.e. CPU time and I/O time. The
CPU time is the time taken by CPU to execute a process and I/O time is the time taken by the process
for I/O operations such as some file operation like read and write. Generally, our computer system
wants to execute a number of processes at a time. But it is not possible. You can run only one process
at a time in a processor. But this can result in some problems.

Suppose we have a single processor system and we have 5 processes P1, P2, P3, P4, and P5 that is to
be executed by the CPU. Since the CPU can execute only one process at a time, so it starts with the
process P1 and after some time of execution of process P1, the process P1 requires some I/O
operation. So, it leaves the CPU and starts performing that I/O operation. Now, the CPU will wait for
the process P1 to come back for its execution and the CPU will be in an idle state for that period of
time. But at the same time, other processes i.e. P2, P3, P4, and P5 are waiting for there execution.
Our CPU is in idle state and this is a very expensive thing. So, why to keep the CPU in the idle state?
What we can do is, if the process P1 wants to perform some I/O operation then let the process P1 do
the I/O job and at the same time, the CPU will be given to the process P2 and if the process P2 also
requires some I/O operation, then the CPU will be given to process P3 and so on. This is
called Context Switching . Once the I/O work is done by the processes then the CPU can resume the
working of that process(i.e. the Process P1 and P2) and by doing so the CPU will never go into the idle
state. This concept of effective CPU utilization is called Multiprogramming .

So, in a multiprogramming system, the CPU executes some part of one program, then some part of
another program, and so on. By doing so, the CPU will never go into the idle state unless there is no
process ready to execute at the time of Context Switching.
Advantages of Multiprogramming

 Very high CPU utilization as the CPU will never be idle unless there is no process to execute.

 Less waiting time for the processes.

 Can be used in a Multiuser system. A Multiuser system allows different users that are on
different computers to access the same CPU and this, in turn, result in Multiprogramming.

Disadvantages of Multiprogramming

 Since you have to perform Context Switching, so you need to have some process scheduling
technique that will tell the CPU which process to take for execution and it is difficult.

 Here, CPU is executing some part of one process, then some part of other and so on. So, in
this case, the memory will be divided into small parts as each process require some memory
and this will result in memory fragmentation. So, no or less continuous memory will be
available.

Multiprocessing
As we know that in a uni-processor system, the processor can execute only one process at a time. But
when your system is having a lot of work to do and one processor is very less to perform all those
work in the required unit of time, then we can use more than one processors in the same system.

So, two or more processors present in the same computer, sharing the system bus, memory, and
other I/O is said to be Multiprocessing System.
Suppose, we are having 5 processes P1, P2, P3, P4, and P5. In a uni-processor system, only one
process can be executed at a time and after its execution, the next process will be executed and so
on. But in a multiprocessor system, the different process can be assigned to different processors and
this, in turn, decreases the overall process execution time by the system. A dual-processor system can
execute two processes at a time while a quad-processor can execute four processes at a time.

Advantages of Multiprocessing

 Since more than one processors are working at a time, so more work is done in a shorter
period of time. Throughput will be increased. You can read more about throughput
from here .

 We have more than one processor, so if one processor is not working then the job can be
done with the help of other processors. This, in turn, increases reliability.

 If you are providing lots of work on one processor then it will result in more battery drain.
But if the work is divided into various processors then it will provide a better battery
efficiency.

 Multiprocessing is an example of true parallel processing i.e. more than one processes
executing at the same time.

Disadvantages of Multiprocessing

 As more than processors are working at a particular instant of time. So, the coordination
between these is very complex.

 Since, the buses, memory, and I/O devices are shared. So, if some processors are using some
I/O then another processor has to wait for its turn and this will result in the reduction of
throughput.

 To have the efficient working of all the processors at a time, we need to have a large main
memory and this, in turn, increase the cost.

Multitasking
If the CPU is allocated to such a process that is taking a lot of time then other processes will have to
wait for the execution of that process and this will result in long waiting of processes for resource
allocation.

For example, if process P1 is taking 20 seconds of CPU time and the CPU is allocated to P1. Now, if
some process P2 comes that requires 1 second of CPU time, then P2 have to wait for 20 seconds
irrespective of the fact that it requires only 1 second of CPU time.

What we can do here is, we can set a time quantum and CPU will be given to each process for that
amount of time only and after that, the CPU will be given to some other process that is ready for
execution. So, in our above example, if the decided time quantum is 2 seconds, then initially, the
process P1 will be allocated the CPU for 2 seconds and then it will be given to process P2. The process
P2 will complete its execution in 1 second and then the CPU will be given to process P1 again. Since
there is no other process available for execution, the process P1 can continue to execute for its
remaining time i.e. 18 seconds. This is called time-sharing. And the concept of time-sharing between
various processes is called Multitasking .

Multitasking is Multiprogramming with time-sharing.


Here the switching between processes is so quick that it gives an illusion that all the processes are
being executed at the same time.
For multitasking, firstly there should be multiprogramming and secondly, there should be time-
sharing.

Advantages of Multitasking

 Since each process is given a particular time quantum for execution. So, it will reduce
starvation.

 It provides an illusion to the user that he/she is using multiple programmes at the same time.

Disadvantages of Multitasking

 Every process will be given a fixed time quantum in one cycle. So, the high priority process
will also have to wait.

 If the processor is slow and the work is very large, then it can't be run smoothly. It requires
more processing power.

Multiprogramming vs Multiprocessing vs Multitasking


We have seen the concepts of Multiprogramming, Multiprocessing, Multitasking. So, when we do the
context switching between various processes then it is called the multiprogramming system. It is
done for better CPU utilization and it makes sure that the CPU never goes in the idle state. While the
multitasking is a process of multiprogramming with a time-sharing concept where every process is
given some time quantum and after that time quantum the CPU is then provided to other processes.
On the other hand, Multiprocessing is the use of more than one processors in the same system so
that true parallel processing can be achieved.

What is a Process in Operating System and what are the different states of a Process?

In the Operating System, a Process is something that is currently under execution. So, an active program
can be called a Process. For example, when you want to search something on web then you start a
browser. So, this can be process. Another example of process can be starting your music player to listen
to some cool music of your choice.
A Process has various attributes associated with it. Some of the attributes of a Process are:
 Process Id: Every process will be given an id called Process Id to uniquely identify that process
from the other processes.
 Process state: Each and every process has some states associated with it at a particular instant
of time. This is denoted by process state. It can be ready, waiting, running, etc.
 CPU scheduling information: Each process is executed by using some process scheduling
algorithms like FCSF, Round-Robin, SJF, etc.
 I/O information: Each process needs some I/O devices for their execution. So, the information
about device allocated and device need is crucial.
States of a Process
During the execution of a process, it undergoes a number of states. So, in this section of the blog, we will
learn various states of a process during its lifecycle.
 New State: This is the state when the process is just created. It is the first state of a process.
 Ready State: After the creation of the process, when the process is ready for its execution then
it goes in the ready state. In a ready state, the process is ready for its execution by the CPU but it
is waiting for its turn to come. There can be more than one process in the ready state.
 Ready Suspended State: There can be more than one process in the ready state but due to
memory constraint, if the memory is full then some process from the ready state gets placed in
the ready suspended state.
 Running State: Amongst the process present in the ready state, the CPU chooses one process
amongst them by using some CPU scheduling algorithm. The process will now be executed by
the CPU and it is in the running state.
 Waiting or Blocked State: During the execution of the process, the process might require some
I/O operation like writing on file or some more priority process might come. In these situations,
the running process will have to go into the waiting or blocked state and the other process will
come for its execution. So, the process is waiting for something in the waiting state.
 Waiting Suspended State: When the waiting queue of the system becomes full then some of the
processes will be sent to the waiting suspended state.
 Terminated State: After the complete execution of the process, the process comes into the
terminated state and the information related to this process is deleted.
The following image will show the flow of a process from the new state to the terminated state.

In the above image, you can see that when a process is created then it goes into the new state. After the
new state, it goes into the ready state. If the ready queue is full, then the process will be shifted to the
ready suspended state. From the ready sate, the CPU will choose the process and the process will be
executed by the CPU and will be in the running state. During the execution of the process, the process
may need some I/O operation to perform. So, it has to go into the waiting state and if the waiting state is
full then it will be sent to the waiting suspended state. From the waiting state, the process can go to the
ready state after performing I/O operations. From the waiting suspended state, the process can go to
waiting or ready suspended state. At last, after the complete execution of the process, the process will go
to the terminated state and the information of the process will be deleted.
This is the whole life cycle of a process.

Process Control Block in Operating System

n an Operating System, we have a number of processes present in it. Each process has some information
that is needed by the CPU for the execution of the process. So, we need some kind of data structure to
store information about a particular process.
A Process Control Block or simple PCB is a data structure that is used to store the information of a process
that might be needed to manage the scheduling of a particular process.
So, each process will be given a PCB which is a kind of identification card for a process. All the processes
present in the system will have a PCB associated with it and all these PCBs are connected in a Linked List.
Attributes of a Process Control Block
There are various attributes of a PCB that helps the CPU to execute a particular process. These attributes
are:
 Process Id: A process id is a unique identity of a process. Each process is identified with the help
of the process id.
 Program Counter: The program counter, points to the next instruction that is to be executed by
the CPU. It is used to find the next instruction that is to be executed.
 Process State: A process can be in any state out of the possible states of a process. So, the CPU
needs to know about the current state of a process, so that its execution can be done easily. You
can learn more about process state from here .
 Priority: There is a priority associated with each process. Based on that priority the CPU finds
which process is to be executed first. Higher priority process will be executed first.
 General-purpose Registers: During the execution of a process, it deals with a number of data
that are being used and changed by the process. But in most of the cases, we have to stop the
execution of a process to start another process and after some times, the previous process
should be resumed once again. Since the previous process was dealing with some data and had
changed the data so when the process resumes then it should use that data only. These data are
stored in some kind of storage units called registers.
 CPU Scheduling Information: It indicates the information about the process scheduling
algorithms that are being used by the CPU for the process.
 List of opened files: A process can deal with a number of files, so the CPU should maintain a list
of files that are being opened by a process to make sure that no other process can open the file
at the same time.
 List of I/O devices: A process may need a number of I/O devices to perform various tasks. So, a
proper list should be maintained that shows which I/O device is being used by which process.
These are the attributes of a Process Control Block and these pieces of information are needed to have
detailed info about the process and this, in turn, results in better execution of the process.

What is Long-Term, Short-Term, and Medium-Term Scheduler?

In the Operating System, CPU schedulers are used to handle the scheduling of various processes that are
coming for its execution by the CPU. Schedulers are responsible for transferring a process from one state
to the other. Basically, we have three types of schedulers i.e.
1. Long-Term Scheduler
2. Short-Term Scheduler
3. Medium-Term Scheduler
In this blog, we will learn about these schedulers and we will see the difference between them. Also, at
the end of the blog, we will look where these schedulers are placed in the Process State Diagram. So, let's
get started.
Long-Term Scheduler
Long-Term schedulers are those schedulers whose decision will have a long-term effect on the
performance. The duty of the long-term scheduler is to bring the process from the JOB pool to the Ready
state for its execution.
Long-Term Scheduler is also called Job Scheduler and is responsible for controlling the Degree of
Multiprogramming i.e. the total number of processes that are present in the ready state.
So, the long-term scheduler decides which process is to be created to put into the ready state.
Effect on performance
 The long term scheduler is responsible for creating a balance between the I/O bound(a process
is said to be I/O bound if the majority of the time is spent on the I/O operation) and CPU
bound(a process is said to be CPU bound if the majority of the time is spent on the CPU). So, if
we create processes which are all I/O bound then the CPU might not be used and it will remain
idle for most of the time. This is because the majority of the time will be spent on the I/O
operation.
 So, if we create processes that are having high a CPU bound or a perfect balance between the
I/O and CPU bound, then the overall performance of the system will be increased.

Short-Term Scheduler
Short-term schedulers are those schedulers whose decision will have a short-term effect on the
performance of the system. The duty of the short-term scheduler is to schedule the process from the
ready state to the running state. This is the place where all the scheduling algorithms are used i.e. it can
be FCFS or Round-Robin or SJF or any other scheduling algorithm.
Short-Term Scheduler is also known as CPU scheduler and is responsible for selecting one process from
the ready state for scheduling it on the running state.
Effect on performance
 The choice of the short-term scheduler is very important for the performance of the system. If
the short-term scheduler only selects a process that is having very high burst time(learn more
about burst time from here ) then the other process may go into the condition of
starvation(learn more about starvation from here ). So, be specific when you are choosing short-
term scheduler because the performance of the system is our highest priority.
The following image shows the scheduling of processes using the long-term and short-term schedulers.

Medium-Term Schedulers
Sometimes, you need to send the running process to the ready state or to the wait/block state. For
example, in the round-robin process, after a fixed time quantum, the process is again sent to the ready
state from the running state. So, these things are done with the help of Medium-Term schedulers.
Medium-term schedulers are those schedulers whose decision will have a mid-term effect on the
performance of the system. It is responsible for swapping of a process from the Main Memory to
Secondary Memory and vice-versa.
It is helpful in maintaining a perfect balance between the I/O bound and the CPU bound. It reduces the
degree of multiprogramming.
The following diagram will give a brief about the working of the medium-term schedulers.

Long-term vs Short-term vs Medium-term Schedulers


Following is the difference between the long-term, short-term, and medium-term schedulers:
Place of schedulers in the Process State Diagram
The Process State Diagram is used to display the flow of processes from one state to other. In this portion
of the blog, we will see the position of long-term, short-term, and medium-term schedulers in the
Process State Diagram. Following is the image of the same:

Process scheduling algorithms in the Operating System


In a system, there are a number of processes that are present in different states at a particular time.
Some processes may be in the waiting state, others may be in the running state and so on. Have you ever
thought how CPU selects one process out of some many processes for execution? Yes, you got it right.
CPU uses some kind of process scheduling algorithms to select one process for its execution amongst so
many processes. The process scheduling algorithms are used to maximize CPU utilization by increasing
throughput. In this blog, we will learn about various process scheduling algorithms used by CPU to
schedule a process.
But before starting this blog, if you are not familiar with Burst time, Arrival time, Exit time, Response
time, Waiting time, Turnaround time, and Throughput, then you should first learn these topics by reading
the blog from here . Also, learn about Preemptive and Non-Preemptive scheduling from here .
Since you are done with the prerequisites of this blog, let's get started by learning different process
scheduling algorithms.
First Come First Serve (FCFS)
As the name suggests, the process coming first in the ready state will be executed first by the CPU
irrespective of the burst time or the priority. This is implemented by using the First In First Out
(FIFO) queue. So, what happens is that, when a process enters into the ready state, then the PCB of that
process will be linked to the tail of the queue and the CPU starts executing the processes by taking the
process from the head of the queue (learn more about PCB from here ). If the CPU is allocated to a
process then it can't be taken back until it finishes the execution of that process.
Example:

In the above example, you can see that we have three processes P1, P2, and P3, and they are coming in
the ready state at 0ms, 2ms, and 2ms respectively. So, based on the arrival time, the process P1 will be
executed for the first 18ms. After that, the process P2 will be executed for 7ms and finally, the process P3
will be executed for 10ms. One thing to be noted here is that if the arrival time of the processes is the
same, then the CPU can select any process.
---------------------------------------------
| Process | Waiting Time | Turnaround Time |
---------------------------------------------
| P1 | 0ms | 18ms |
| P2 | 16ms | 23ms |
| P3 | 23ms | 33ms |
---------------------------------------------
Total waiting time: (0 + 16 + 23) = 39ms
Average waiting time: (39/3) = 13ms

Total turnaround time: (18 + 23 + 33) = 74ms


Average turnaround time: (74/3) = 24.66ms
Advantages of FCFS:
 It is the most simple scheduling algorithm and is easy to implement.
Disadvantages of FCFS:
 This algorithm is non-preemptive so you have to execute the process fully and after that other
processes will be allowed to execute.
 Throughput is not efficient.
 FCFS suffers from the Convey effect i.e. if a process is having very high burst time and it is
coming first, then it will be executed first irrespective of the fact that a process having very less
time is there in the ready state.

Shortest Job First (Non-preemptive)


In the FCFS, we saw if a process is having a very high burst time and it comes first then the other process
with a very low burst time have to wait for its turn. So, to remove this problem, we come with a new
approach i.e. Shortest Job First or SJF.
In this technique, the process having the minimum burst time at a particular instant of time will be
executed first. It is a non-preemptive approach i.e. if the process starts its execution then it will be fully
executed and then some other process will come.
Example:
In the above example, at 0ms, we have only one process i.e. process P2, so the process P2 will be
executed for 4ms. Now, after 4ms, there are two new processes i.e. process P1 and process P3. The burst
time of P1 is 5ms and that of P3 is 2ms. So, amongst these two, the process P3 will be executed first
because its burst time is less than P1. P3 will be executed for 2ms. Now, after 6ms, we have two
processes with us i.e. P1 and P4 (because we are at 6ms and P4 comes at 5ms). Amongst these two, the
process P4 is having a less burst time as compared to P1. So, P4 will be executed for 4ms and after that
P1 will be executed for 5ms. So, the waiting time and turnaround time of these processes will be:
---------------------------------------------
| Process | Waiting Time | Turnaround Time |
---------------------------------------------
| P1 | 7ms | 12ms |
| P2 | 0ms | 4ms |
| P3 | 0ms | 2ms |
| P4 | 1ms | 5ms |
---------------------------------------------
Total waiting time: (7 + 0 + 0 + 1) = 8ms
Average waiting time: (8/4) = 2ms

Total turnaround time: (12 + 4 + 2 + 5) = 23ms


Average turnaround time: (23/4) = 5.75ms
Advantages of SJF (non-preemptive):
 Short processes will be executed first.
Disadvantages of SJF (non-preemptive):
 It may lead to starvation if only short burst time processes are coming in the ready state(learn
more about starvation from here ).

Shortest Job First (Preemptive)


This is the preemptive approach of the Shortest Job First algorithm. Here, at every instant of time, the
CPU will check for some shortest job. For example, at time 0ms, we have P1 as the shortest process. So,
P1 will execute for 1ms and then the CPU will check if some other process is shorter than P1 or not. If
there is no such process, then P1 will keep on executing for the next 1ms and if there is some process
shorter than P1 then that process will be executed. This will continue until the process gets executed.
This algorithm is also known as Shortest Remaining Time First i.e. we schedule the process based on the
shortest remaining time of the processes.
Example:
In the above example, at time 1ms, there are two processes i.e. P1 and P2. Process P1 is having burst
time as 6ms and the process P2 is having 8ms. So, P1 will be executed first. Since it is a preemptive
approach, so we have to check at every time quantum. At 2ms, we have three processes i.e. P1(5ms
remaining), P2(8ms), and P3(7ms). Out of these three, P1 is having the least burst time, so it will continue
its execution. After 3ms, we have four processes i.e P1(4ms remaining), P2(8ms), P3(7ms), and P4(3ms).
Out of these four, P4 is having the least burst time, so it will be executed. The process P4 keeps on
executing for the next three ms because it is having the shortest burst time. After 6ms, we have 3
processes i.e. P1(4ms remaining), P2(8ms), and P3(7ms). So, P1 will be selected and executed. This
process of time comparison will continue until we have all the processes executed. So, waiting and
turnaround time of the processes will be:
---------------------------------------------
| Process | Waiting Time | Turnaround Time |
---------------------------------------------
| P1 | 3ms | 9ms |
| P2 | 16ms | 24ms |
| P3 | 8ms | 15ms |
| P4 | 0ms | 3ms |
---------------------------------------------
Total waiting time: (3 + 16 + 8 + 0) = 27ms
Average waiting time: (27/4) = 6.75ms

Total turnaround time: (9 + 24 + 15 + 3) = 51ms


Average turnaround time: (51/4) = 12.75ms
Advantages of SJF (preemptive):
 Short processes will be executed first.
Disadvantages of SJF (preemptive):
 It may result in starvation if short processes keep on coming.

Round-Robin
In this approach of CPU scheduling, we have a fixed time quantum and the CPU will be allocated to a
process for that amount of time only at a time. For example, if we are having three process P1, P2, and
P3, and our time quantum is 2ms, then P1 will be given 2ms for its execution, then P2 will be given 2ms,
then P3 will be given 2ms. After one cycle, again P1 will be given 2ms, then P2 will be given 2ms and so
on until the processes complete its execution.
It is generally used in the time-sharing environments and there will be no starvation in case of the round-
robin.
Example:
In the above example, every process will be given 2ms in one turn because we have taken the time
quantum to be 2ms. So process P1 will be executed for 2ms, then process P2 will be executed for 2ms,
then P3 will be executed for 2 ms. Again process P1 will be executed for 2ms, then P2, and so on. The
waiting time and turnaround time of the processes will be:
---------------------------------------------
| Process | Waiting Time | Turnaround Time |
---------------------------------------------
| P1 | 13ms | 23ms |
| P2 | 10ms | 15ms |
| P3 | 13ms | 21ms |
---------------------------------------------
Total waiting time: (13 + 10 + 13) = 36ms
Average waiting time: (36/3) = 12ms

Total turnaround time: (23 + 15 + 21) = 59ms


Average turnaround time: (59/3) = 19.66ms
Advantages of round-robin:
 No starvation will be there in round-robin because every process will get chance for its
execution.
 Used in time-sharing systems.
Disadvantages of round-robin:
 We have to perform a lot of context switching here, which will keep the CPU idle(learn more
about context switching from here ).

Priority Scheduling (Non-preemptive)


In this approach, we have a priority number associated with each process and based on that priority
number the CPU selects one process from a list of processes. The priority number can be anything. It is
just used to identify which process is having a higher priority and which process is having a lower priority.
For example, you can denote 0 as the highest priority process and 100 as the lowest priority process.
Also, the reverse can be true i.e. you can denote 100 as the highest priority and 0 as the lowest priority.
Example:
In the above example, at 0ms, we have only one process P1. So P1 will execute for 5ms because we are
using non-preemption technique here. After 5ms, there are three processes in the ready state i.e.
process P2, process P3, and process P4. Out to these three processes, the process P4 is having the highest
priority so it will be executed for 6ms and after that, process P2 will be executed for 3ms followed by the
process P1. The waiting and turnaround time of processes will be:
---------------------------------------------
| Process | Waiting Time | Turnaround Time |
---------------------------------------------
| P1 | 0ms | 5ms |
| P2 | 10ms | 13ms |
| P3 | 12ms | 20ms |
| P4 | 2ms | 8ms |
---------------------------------------------
Total waiting time: (0 + 10 + 12 + 2) = 24ms
Average waiting time: (24/4) = 6ms

Total turnaround time: (5 + 13 + 20 + 8) = 46ms


Average turnaround time: (46/4) = 11.5ms
Advantages of priority scheduling (non-preemptive):
 Higher priority processes like system processes are executed first.
Disadvantages of priority scheduling (non-preemptive):
 It can lead to starvation if only higher priority process comes into the ready state.
 If the priorities of more two processes are the same, then we have to use some other scheduling
algorithm.

Multilevel Queue Scheduling


In multilevel queue scheduling, we divide the whole processes into some batches or queues and then
each queue is given some priority number. For example, if there are four processes P1, P2, P3, and P4,
then we can put process P1 and P4 in queue1 and process P2 and P3 in queue2. Now, we can assign some
priority to each queue. So, we can take the queue1 as having the highest priority and queue2 as the
lowest priority. So, all the processes of the queue1 will be executed first followed by queue2. Inside the
queue1, we can apply some other scheduling algorithm for the execution of processes of queue1. Similar
is with the case of queue2.
So, multiple queues for processes are maintained that are having common characteristics and each
queue has its own priority and there is some scheduling algorithm used in each of the queues.
Example:
In the above example, we have two queues i.e. queue1 and queue2. Queue1 is having higher priority and
queue1 is using the FCFS approach and queue2 is using the round-robin approach(time quantum = 2ms).
Since the priority of queue1 is higher, so queue1 will be executed first. In the queue1, we have two
processes i.e. P1 and P4 and we are using FCFS. So, P1 will be executed followed by P4. Now, the job of
the queue1 is finished. After this, the execution of the processes of queue2 will be started by using the
round-robin approach.

Multilevel Feedback Queue Scheduling


Multilevel feedback queue scheduling is similar to multilevel queue scheduling but here the processes
can change their queue also. For example, if a process is in queue1 initially then after partial execution of
the process, it can go into some other queue.
In a multilevel feedback queue, we have a list of queues having some priority and the higher priority
queue is always executed first. Let's assume that we have two queues i.e. queue1 and queue2 and we are
using round-robin for these i.e. time quantum for queue1 is 2 ms and for queue2 is 3ms. Now, if a
process starts executing in the queue1 then if it gets fully executed in 2ms then it is ok, its priority will not
be changed. But if the execution of the process will not be completed in the time quantum of queue1,
then the priority of that process will be reduced and it will be placed in the lower priority queue i.e.
queue2 and this process will continue.
While executing a lower priority queue, if a process comes into the higher priority queue, then the
execution of that lower priority queue will be stopped and the execution of the higher priority queue will
be started. This can lead to starvation because if the process keeps on going into the higher priority
queue then the lower priority queue keeps on waiting for its turn.

What is Burst time, Arrival time, Exit time, Response time, Waiting time,
Turnaround time, and Throughput?

When we are dealing with some CPU scheduling algorithms then we encounter with some confusing
terms like Burst time, Arrival time, Exit time, Waiting time, Response time, Turnaround time, and
throughput. These parameters are used to find the performance of a system. So, in this blog, we will
learn about these parameters. Let's get started one by one.

Burst time
Every process in a computer system requires some amount of time for its execution. This time is both the
CPU time and the I/O time. The CPU time is the time taken by CPU to execute the process. While the I/O
time is the time taken by the process to perform some I/O operation. In general, we ignore the I/O time
and we consider only the CPU time for a process. So, Burst time is the total time taken by the process
for its execution on the CPU.
Arrival time
Arrival time is the time when a process enters into the ready state and is ready for its execution.

Here in the above example, the arrival time of all the 3 processes are 0 ms, 1 ms, and 2 ms respectively.

Exit time
Exit time is the time when a process completes its execution and exit from the system.

Response time
Response time is the time spent when the process is in the ready state and gets the CPU for the first
time. For example, here we are using the First Come First Serve CPU scheduling algorithm for the below 3
processes:

Here, the response time of all the 3 processes are:


 P1: 0 ms
 P2: 7 ms because the process P2 have to wait for 8 ms during the execution of P1 and then after
it will get the CPU for the first time. Also, the arrival time of P2 is 1 ms. So, the response time will
be 8-1 = 7 ms.
 P3: 13 ms because the process P3 have to wait for the execution of P1 and P2 i.e. after 8+7 = 15
ms, the CPU will be allocated to the process P3 for the first time. Also, the arrival of P3 is 2 ms.
So, the response time for P3 will be 15-2 = 13 ms.

Response time = Time at which the process gets the CPU for the first time - Arrival time

Waiting time
Waiting time is the total time spent by the process in the ready state waiting for CPU. For example,
consider the arrival time of all the below 3 processes to be 0 ms, 0 ms, and 2 ms and we are using the
First Come First Serve scheduling algorithm.
Then the waiting time for all the 3 processes will be:
 P1: 0 ms
 P2: 8 ms because P2 have to wait for the complete execution of P1 and arrival time of P2 is 0 ms.
 P3: 13 ms becuase P3 will be executed after P1 and P2 i.e. after 8+7 = 15 ms and the arrival time
of P3 is 2 ms. So, the waiting time of P3 will be: 15-2 = 13 ms.

Waiting time = Turnaround time - Burst time

In the above example, the processes have to wait only once. But in many other scheduling algorithms,
the CPU may be allocated to the process for some time and then the process will be moved to the waiting
state and again after some time, the process will get the CPU and so on.
There is a difference between waiting time and response time. Response time is the time spent between
the ready state and getting the CPU for the first time. But the waiting time is the total time taken by the
process in the ready state. Let's take an example of a round-robin scheduling algorithm. The time
quantum is 2 ms.

In the above example, the response time of the process P2 is 2 ms because after 2 ms, the CPU is
allocated to P2 and the waiting time of the process P2 is 4 ms i.e turnaround time - burst time (10 - 6 = 4
ms).

Turnaround time
Turnaround time is the total amount of time spent by the process from coming in the ready state for the
first time to its completion.
Turnaround time = Burst time + Waiting time
or
Turnaround time = Exit time - Arrival time
For example, if we take the First Come First Serve scheduling algorithm, and the order of arrival of
processes is P1, P2, P3 and each process is taking 2, 5, 10 seconds. Then the turnaround time of P1 is 2
seconds because when it comes at 0th second, then the CPU is allocated to it and so the waiting time of
P1 is 0 sec and the turnaround time will be the Burst time only i.e. 2 seconds. The turnaround time of P2
is 7 seconds because the process P2 have to wait for 2 seconds for the execution of P1 and hence the
waiting time of P2 will be 2 seconds. After 2 seconds, the CPU will be given to P2 and P2 will execute its
task. So, the turnaround time will be 2+5 = 7 seconds. Similarly, the turnaround time for P3 will be 17
seconds because the waiting time of P3 is 2+5 = 7 seconds and the burst time of P3 is 10 seconds. So,
turnaround time of P3 is 7+10 = 17 seconds.
Different CPU scheduling algorithms produce different turnaround time for the same set of processes.
This is because the waiting time of processes differs when we change the CPU scheduling algorithm.

Throughput
Throughput is a way to find the efficiency of a CPU. It can be defined as the number of processes
executed by the CPU in a given amount of time. For example, let's say, the process P1 takes 3 seconds for
execution, P2 takes 5 seconds, and P3 takes 10 seconds. So, throughput, in this case, the throughput will
be (3+5+10)/3 = 18/3 = 6 seconds.

What is Starvation and Aging?


Starvation
If you closely look at the concept of Priority scheduling, then you might have noticed one thing. What if
the priority of some process is very low and the higher priority processes keep on coming and the CPU is
allocated to that higher priority processes and the low priority process keeps on waiting for its turn. Let's
have an example:

In the above example, the process P2 is having the highest priority and the process P1 is having the
lowest priority. In general, we have a number of processes that are in the ready state for its execution.
So, as time passes, if only that processes are coming in the CPU that are having a higher priority than the
process P1, then the process P1 will keep on waiting for its turn for CPU allocation and it will never get
CPU because all the other processes are having higher priority than P1. This is called Starvation.
Starvation is a phenomenon in which a process that is present in the ready state and has low priority,
keeps on waiting for the CPU allocation because some other process with higher priority comes with
due respect to time.
So, starvation should be removed because if some process is in the ready state then we should provide
CPU to it. Since the process is of low priority so we can take our time for CPU allocation to that process
but we must ensure that the CPU is allocated.

Aging
To avoid starvation, we use the concept of Aging. In Aging, after some fixed amount of time quantum, we
increase the priority of the low priority processes. By doing so, as time passes, the lower priority process
becomes a higher priority process.
For example, if a process P is having a priority number as 75 at 0 ms. Then after every 5 ms(you can use
any time quantum), we can decrease the priority number of the process P by 1(here also instead of 1, you
can take any other number). So, after 5 ms, the priority of the process P will be 74. Again after 5 ms, we
will decrease the priority number of process P by 1. So, after 10 ms, the priority of the process P will
become 73 and this process will continue. After a certain period of time, the process P will become a high
priority process when the priority number comes closer to 0 and the process P will get the CPU for its
execution. In this way, the lower priority process also gets the CPU. No doubt the CPU is allocated after a
very long time but since the priority of the process is very low so, we are not that much concerned about
the response time of the process(read more about response time from here ). The only thing that we are
taking care of is starvation.
So, we are Aging our low priority process to make it a high priority process and as a result, to allocate
the CPU for it.
Whenever you are using Priority scheduling algorithm or Shortest Job First algorithm, then make sure to
use the concept of Aging, otherwise, your process will end up with starvation.

Difference between Mutex and Semaphore in Operating System


In an Operating System, there are a number of processes that are ready to be executed at a particular
instant of time. These processes require various resources for their execution. So, for this, we have
shared resources in our system that can be shared between these processes. But one thing that should
be kept in mind is that the resources are shared but it should not be used simultaneously by all the
processes. For example, if the system is having a printer, then this printer is shared with all the processes
but at a time, only one process can use the printer. No two processes should be allowed to use the
printer at the same instant of time. This is called Process Synchronization .

Process Synchronization and Critical Section


In an Operating System, we have a number of processes and these processes require a number of
resources. Now, think of a situation where we have two processes and these processes are using the
same variable "a". They are reading the variable and then updating the value to the variable and finally
writing the data in the memory.
SomeProcess(){
...
read(a) //instruction 1
a = a + 5 //instruction 2
write(a) //instruction 3
...
}
In the above, you can see that a process after doing some operations will have to read the value of "a",
then increment the value of "a" by 5 and at last write the value of "a" in the memory. Now, we have two
processes P1 and P2 that needs to be executed. Let's take the following two cases and also assume that
the value of "a" is 10 initially
1. In this case, process P1 will be executed fully (i.e. all the three instructions) and after that, the
process P2 will be executed. So, the process P1 will first read the value of "a" to be 10 and then
increment the value by 5 and make it to 15. Lastly, this value will be updated in the memory. So,
the current value of "a" is 15. Now, the process P2 will read the value i.e. 15, increment with
5(15+5 = 20) and finally write it to the memory i.e. the new value of "a" is 20. Here, in this case,
the final value of "a" is 20.
2. In this case, let's assume that the process P1 starts executing. So, it reads the value of "a" from
the memory and that value is 10(initial value of "a" is taken to be 10). Now, at this time, context
switching happens between process P1 and P2(learn more about context switching from here ).
Now, P2 will be in the running state and P1 will be in the waiting state and the context of the P1
process will be saved. As the process P1 didn't change the value of "a", so, P2 will also read the
value of "a" to be 10. It will then increment the value of "a" by 5 and make it to 15 and then save
it to the memory. After the execution of the process P2, the process P1 will be resumed and the
context of the P1 will be read. So, the process P1 is having the value of "a" as 10(because P1 has
already executed the instruction 1). It will then increment the value of "a" by 5 and write the
final value of "a" in the memory i.e. a = 15. Here, the final value of "a" is 15.
In the above two cases, after the execution of the two processes P1 and P2, the final value of "a" is
different i.e. in 1st case it is 20 and in 2nd case, it is 15. What's the reason behind this?
The processes are using the same resource here i.e. the variable "a". In the first approach, the process P1
executes first and then the process P2 starts executing. But in the second case, the process P1 was
stopped after executing one instruction and after that the process P2 starts executing. And here both the
processes are dealing on the same resource i.e. variable "a" at the same time. This is the critical
section of the process. So, there must be some synchronization between the processes when they are
using shared resources.
The shared resources can be used by all the processes but the processes should make sure that at a
particular time, only one process should be using that shared resource. This is called process
synchronization.
So, to apply process synchronization, two methods are used. They are:
1. Mutex
2. Semaphore
Let's look at them one by one.

Mutex
Mutex or Mutual Exclusion Object is used to give access to a resource to only one process at a time. The
mutex object allows all the processes to use the same resource but at a time, only one process is allowed
to use the resource. Mutex uses the lock-based technique to handle the critical section problem.
Whenever a process requests for a resource from the system, then the system will create a mutex object
with a unique name or ID. So, whenever the process wants to use that resource, then the process
occupies a lock on the object. After locking, the process uses the resource and finally releases the mutex
object. After that, other processes can create the mutex object in the same manner and use it.
By locking the object, that particular resource is allocated to that particular process and no other process
can take that resource. So, in the critical section, no other processes are allowed to use the shared
resource. In this way, the process synchronization can be achieved with the help of a mutex object.

Semaphore
Semaphore is an integer variable S , that is initialized with the number of resources present in the system
and is used for process synchronization. It uses two functions to change the value
of S i.e. wait() and signal() . Both these functions are used to modify the value of semaphore but the
functions allow only one process to change the value at a particular time i.e. no two processes can
change the value of semaphore simultaneously. There are two categories of semaphores i.e. Counting
semaphores and Binary semaphores .
In Counting semaphores , firstly, the semaphore variable is initialized with the number of resources
available. After that, whenever a process needs some resource, then the wait() function is called and the
value of the semaphore variable is decreased by one. The process then uses the resource and after using
the resource, the signal() function is called and the value of the semaphore variable is increased by one.
So, when the value of the semaphore variable goes to 0 i.e all the resources are taken by the process and
there is no resource left to be used, then if some other process wants to use resources then that process
has to wait for its turn. In this way, we achieve the process synchronization.
In Binary semaphores , the value of the semaphore variable will be 0 or 1. Initially, the value of
semaphore variable is set to 1 and if some process wants to use some resource then the wait() function is
called and the value of the semaphore is changed to 0 from 1. The process then uses the resource and
when it releases the resource then the signal() function is called and the value of the semaphore variable
is increased to 1. If at a particular instant of time, the value of the semaphore variable is 0 and some
other process wants to use the same resource then it has to wait for the release of the resource by the
previous process. In this way, process synchronization can be achieved. It is similar to mutex but here
locking is not performed.

Difference between Mutex and Semaphore


Till now, we have learned about mutex and semaphore. Most of you might have guessed the difference
between these two. Let's have a look into the difference between mutex and semaphore:
 Mutex uses a locking mechanism i.e. if a process wants to use a resource then it locks the
resource, uses it and then release it. But on the other hand, semaphore uses a signalling
mechanism where wait() and signal() methods are used to show if a process is releasing a
resource or taking a resource.
 A mutex is an object but semaphore is an integer variable.
 In semaphore, we have wait() and signal() functions. But in mutex, there is no such function.
 A mutex object allows multiple process threads to access a single shared resource but only one
at a time. On the other hand, semaphore allows multiple process threads to access the finite
instance of the resource until available.
 In mutex, the lock can be acquired and released by the same process at a time. But the value of
the semaphore variable can be modified by any process that needs some resource but only one
process can change the value at a time.

What is Deadlock and what are its four necessary conditions?


What is Deadlock?
Deadlock is a situation where two or more processes are waiting for each other. For example, let us
assume, we have two processes P1 and P2. Now, process P1 is holding the resource R1 and is waiting for
the resource R2. At the same time, the process P2 is having the resource R2 and is waiting for the
resource R1. So, the process P1 is waiting for process P2 to release its resource and at the same time, the
process P2 is waiting for process P1 to release its resource. And no one is releasing any resource. So, both
are waiting for each other to release the resource. This leads to infinite waiting and no work is done here.
This is called Deadlock.

If a process is in the waiting state and is unable to change its state because the resources required by the
process is held by some other waiting process, then the system is said to be in Deadlock.
Let's take one real-life example to understand the concept of Deadlock in a better way. Suppose, you are
studying in a school and you are using the bus service also. So, you have to pay two fees i.e. bus fee and
tuition fee. Now, think of a situation, when you go for submitting the bus fee and the accountant says
that you have to submit the tuition fee first and then the bus fee. So, you go to submit the tuition fees on
the other counter and the accountant there said that you have to first submit the bus fees and then the
tuition fees. So, what will you do here? You are in a situation of deadlock here. You don't know what to
submit first, bus fees or tuition fees?

Necessary Conditions of Deadlock


There are four different conditions that result in Deadlock. These four conditions are also known as
Coffman conditions and these conditions are not mutually exclusive. Let's look at them one by one.
 Mutual Exclusion: A resource can be held by only one process at a time. In other words, if a
process P1 is using some resource R at a particular instant of time, then some other process P2
can't hold or use the same resource R at that particular instant of time. The process P2 can make
a request for that resource R but it can't use that resource simultaneously with process P1.

 Hold and Wait: A process can hold a number of resources at a time and at the same time, it can
request for other resources that are being held by some other process. For example, a process
P1 can hold two resources R1 and R2 and at the same time, it can request some resource R3 that
is currently held by process P2.
 No preemption: A resource can't be preempted from the process by another process, forcefully.
For example, if a process P1 is using some resource R, then some other process P2 can't
forcefully take that resource. If it is so, then what's the need for various scheduling algorithm.
The process P2 can request for the resource R and can wait for that resource to be freed by the
process P1.
 Circular Wait: Circular wait is a condition when the first process is waiting for the resource held
by the second process, the second process is waiting for the resource held by the third process,
and so on. At last, the last process is waiting for the resource held by the first process. So, every
process is waiting for each other to release the resource and no one is releasing their own
resource. Everyone is waiting here for getting the resource. This is called a circular wait.

Deadlock will happen if all the above four conditions happen simultaneously.

Difference between Deadlock and Starvation


There is a difference between a Deadlock and Starvation. You shouldn't get confused between these. In
the case of Deadlock, each and every process is waiting for each other to release the resource. But in the
case of starvation, the high priority processes keep on executing and the lower priority processes keep on
waiting for its execution. So, every deadlock is always starvation, but every starvation is not a deadlock.
Deadlock is infinite waiting but starvation is not an infinite waiting. Starvation is long waiting. If the
higher priority processes don't come, then the lower priority process will get a chance to be executed in
case of starvation. So, in the case of starvation, we have long waiting and not infinite waiting.

What are Deadlock handling techniques in Operating System?

To remove deadlock from our system, we need to avoid any one of the above four conditions of
deadlock. So, there are various ways of deadlock handling. Let's see all of them, one by one.
1. Deadlock Prevention
In this method, the system will prevent any deadlock condition to happen i.e. the system will make sure
that at least one of the four conditions of the deadlock will be violated. Since we are preventing any one
of four conditions to happen by applying some techniques. These techniques can be very costly. So, you
should apply deadlock prevention in only those situation which has a drastic change in the system if
deadlock happens.
For example, in hospitals, we have generators or inverters installed. So that in case of a power cut, no
life-saving machines should stop otherwise it can lead to the death of a patient. There can be chances
that in the area of the hospital, the power cut happens rarely. But since it is a case of life-death, then you
must Prevent this by installing generators or inverters. No doubt, you have to bear the cost of
generators. Now, think of other situation, if there is a temple in the same area, then you need not install
generators because here we are not dealing with some life-death situation and the power cut in the area
is also very rare. So, prevention technique should be applied only when there will be a drastic change if
deadlock happens. So, before using the deadlock prevention mechanism, make sure that if deadlock
happens in your system then it will have an adverse effect on your system or not.
Let's see how we can avoid the four conditions of deadlock by using the deadlock prevention technique.
 Mutual Exclusion: Mutual exclusion says that a resource can only be held by one process at a
time. If another process is also demanding the same resource then it has to wait for the
allocation of that resource. So, practically, we can't violate the mutual exclusion for a process
because in general, one resource can perform the work of one process at a time. For example, a
printer can't print documents of two users at the same time.
 Hold and Wait: Hold and wait arises when a process holds some resources and is waiting for
some other resources that are being held by some other waiting process. To avoid this, the
process can acquire all the resources that it needs, before starting its execution and after that, it
starts its execution. In this way, the process need not wait for some resources during its
execution. But this method is not practical because we can't know the resources required by a
process in advance, before its execution. So, another way of avoiding hold and wait can be the
"Do not hold" technique. For example, if the process needs 10 resources R1, R2, R3,...., R10. At a
particular time, we can provide R1, R2, R3, and R4. After performing the jobs on these resources,
the process needs to release these resources and then the other resources will be provided to
the process. In this way, we can avoid the hold and wait condition.
 No Preemption: This is a technique in which a process can't forcefully take the resource of other
processes. But if we found some resource due to which, deadlock is happening in the system,
then we can forcefully preempt that resource from the process that is holding that resource. By
doing so, we can remove the deadlock but there are certain things that should be kept in mind
before using this forcefull approach. If the process is having a very high priority or the process is
a system process, then only the process can forcefully preempt the resources of other
processes. Also, try to preempt the resources of those process which are in the waiting state.
 Circular Wait: Circular wait is a condition in which the first process is waiting for the resource
held by the second process, the second process is waiting for the resource held by the third
process and so on. At last, the last process is waiting for the resource held by the first process.
So, every process is waiting for each other to release the resource. This is called a circular wait.
To avoid this, what we can do is, we can list the number of resources required by a process and
we assign some number or priority to each resource(in our case, we are using R1, R2, R3, and so
on). Now, the process will take the resources in the ascending order. For example, if the process
P1 and P2, requires resource R1 and R2, then initially, both the process will demand the
resource R1 and only one of them will get resource R1 at that time and the other process have
to wait for its turn. So, in this way, both the process will not be waiting for each other. One of
them will be executing and the other will wait for its turn. So, there is no circular wait here.
2. Deadlock Avoidance
In the deadlock avoidance technique, we try to avoid deadlock to happen in our system. Here, the system
wants to be in a safe state always. So, the system maintains a set of data and using that data it decides
whether a new request should be entertained or not. If the system is going into the bad state by taking
that new request, then the system will avoid those kinds of request and will ignore the request. So, if a
request is made for a resource, from a system, then that request should only be approved if the resulting
state of the system is safe i.e. not going into deadlock.
3. Detection and Recovery
In this approach, the CPU assumes that at some point of time, a deadlock will happen in the system and
after that, the CPU will apply some recovery technique to get rid of that deadlock. The CPU periodically
checks for the deadlock. The Resource Allocation Graphs are used to detect the deadlock in a system.
For recovery, the CPU may forcefully take the resource allocated to some process and give it to some
other process but that process should be of high priority or that process must be a system process.
4. Deadlock Ignorance
In most of the systems, deadlock happens rarely. So, why to apply so many detection and recovery
techniques or why to apply some method to prevent deadlock? As these processes of deadlock
prevention are costly, so, the Operating System assumes that the deadlock is never going to happen. It
simply ignores the deadlock. This is the most widely used methods of deadlock handling.
We have to compromise between correctness and performance. In the above three methods, the
correctness is good but the performance of the system is low because the CPU has to check for deadlock
after a regular interval. But if we ignore the deadlock then there might be cases where deadlock can
happen but that is rare of the rarest case. We can simply restart the system and get rid of deadlock if
some deadlock happens in our system. But at the same time, you will lose your data that is not being
saved.
So, you have to think that you want correctness or performance. If you want performance, then your
system should ignore deadlock otherwise you can apply some deadlock prevention technique. It totally
depends on the need of the situation. If your system is dealing with some very very important data and
you can't lose that if deadlock happens then you should definitely go for deadlock prevention.

Banker’s Algorithm
Banker’s Algorithm is a deadlock avoidance algorithm . It is also used for deadlock detection. This
algorithm tells that if any system can go into a deadlock or not by analyzing the currently allocated
resources and the resources required by it in the future. There are various data structures which are used
to implement this algorithm. So, let's learn about these first.
Data Structures used to implement Banker’s Algorithm
1. Available: It is a 1-D array that tells the number of each resource type (instance of resource
type) currently available. Example: Available[R1]= A, means that there are A instances of R1
resources are currently available.
2. Max: It is a 2-D array that tells the maximum number of each resource type required by a
process for successful execution. Example: Max[P1][R1] = A, specifies that the process P1 needs
a maximum of A instances of resource R1 for complete execution.
3. Allocation: It is a 2-D array that tells the number of types of each resource type that has been
allocated to the process. Example: Allocation[P1][R1] = A, means that A instances of resource
type R1 have been allocated to the process P1.
4. Need: It is a 2-D array that tells the number of remaining instances of each resource type
required for execution. Example: Need[P1][R1]= A tells that A instances of R1 resource type are
required for the execution of process P1.
Need[i][j]= Max[i][j] - Allocation[i][j], where i corresponds any process P(i) and j corresponds to any
resouce type R(j)
The Bankers Algorithm consists of the following two algorithms
1. Request-Resource Algorithm
2. Safety Algorithm
Resource- Request Algorithm
Whenever a process makes a request of the resources then this algorithm checks that if the resource can
be allocated or not.
It includes three steps:
1. The algorithm checks that if the request made is valid or not. A request is valid if the number of
requested resources of each resource type is less than the Need( which was declared previously
by the process ). If it is a valid request then step 2 is executed else aborted.
2. Here, the algorithm checks that if the number of requested instances of each resource is less
than the available resources. If not then the process has to wait until sufficient resources are
available else go to step 3.
3. Now, the algorithm assumes that the resources have been allocated and modifies the data
structure accordingly.
Available = Available - Request(i)
Allocation(i) = Allocation(i) + Request(i)
Need(i) = Need(i) - Request(i)
After the allocation of resources, the new state formed may or may not be a safe state. So, the safety
algorithm is applied to check whether the resulting state is a safe state or not.
Safe state: A safe state is a state in which all the processes can be executed in some arbitrary order with
the available resources such that no deadlock occurs.
1. If it is a safe state, then the requested resources are allocated to the process in actual.
2. If the resulting state is an unsafe state then it rollbacks to the previous state and the process is
asked to wait longer.
Safety Algorithm
The safety algorithm is applied to check whether a state is in a safe state or not.
This algorithm involves the following four steps:
1. Suppose currently all the processes are to be executed. Define two data structures as work and
finish as vectors of length m(where m is the length of Available vector)and n(is the number of
processes to be executed).
Work = Available
Finish[i] =false for i = 0, 1, … , n — 1.
2. This algorithm will look for a process that has Need value less than or equal to the Work . So, in this
step, we will find an index i such that
Finish[i] ==false &&
Need[i]<= Work
If no such ‘i’ is present then go to step 4 else to step 3.
3. The process ' i' selected in the above step runs and finishes its execution. Also, the resources allocated
to it gets free. The resources which get free are added to the Work and Finish(i) of the process is set as
true. The following operations are performed:
Work = Work + Allocation
Finish[i] = true
After performing the 3rd step go to step 2.
4. If all the processes are executed in some sequence then it is said to be a safe state. Or, we can say that
if
Finish[i]==true for all i,
then the system is said to be in a safe state .
Let's take an example to understand this more clearly.
Example
Suppose we have 3 processes(A, B, C) and 3 resource types(R1, R2, R3) each having 5 instances.
Suppose at any time t if the snapshot of the system taken is as follows then find the system is in a safe
state or not.

So, the total allocated resources(total_alloc)are [5, 4, 3]. Therefore, the Available( the resources that are
currently available ) resources are
Available = [0, 1, 2]
Now, we will make the Need Matrix for the system according to the given conditions. As we
know, Need(i)=Max(i)-Allocation(i) , so the resultant Need matrix will be as follows:

Now, we will apply the safety algorithm to check that if the given state is a safe state or not.
1. Work=Available=[0, 1, 2]
2. Also Finish[i]=false, for i=0,1,2, are set as false as none of these processes have been executed.
3. Now, we check that Need[i]≤Work . By seeing the above Need matrix we can tell that only B[0,
1, 2] process can be executed. So, process B( i=1 )is allocated the resources and it completes its
execution. After completing the execution, it frees up the resources.
4. Again, Work=Work+Available i.e. Work=[0, 1, 2]+[2, 0,1]= [2, 1, 3] and Finish[1]= true.
5. Now, as we have more instances of resources available we will check that if any other process
resource needs can be satisfied. With the currently available resources[2, 1, 3], we can see that
only process A[1, 2, 1] can be executed. So, process A( i=0 ) is allocated the resources and it
completes its execution. After completing the execution, it frees up the resources.
6. Again, Work=Work+Available i.e. Work=[2, 1, 3]+[1, 2, 1]= [3, 3, 4] and Finish[0]= true.
7. Now, as we have more instances of resources available we will check that if the remaining last
process resource requirement can be satisfied. With the currently available resources[3, 3, 4],
we can see that process C[2, 2, 1] can be executed. So, process C( i=2 ) is allocated the resources
and it completes its execution. After completing the execution, it frees up the resources.
8. Fianlly, Work=Work+Available i.e. Work=[3, 3, 4]+[2, 2, 1]= [5, 5, 5] and Finish[2]= true.
9. Finally, all the resources are free and there exists a safe sequence B, A, C in which all the
processes can be executed. So. the system is in a safe state and deadlock will not occur.
This is how Banker's Algorithm is used to check if the system is in a safe state or not.

What is Fragmentation and what are its types?


In contiguous memory allocation whenever the processes come into RAM, space is allocated to them.
These spaces in RAM are divided either on the basis of fixed partitioning (the size of partitions are fixed
before the process gets loaded into RAM) or dynamic partitioning (the size of the partition is decided at
the run time according to the size of the process). As the process gets loaded and removed from the
memory these spaces get broken into small pieces of memory that it can’t be allocated to the coming
processes. This problem is called fragmentation . In this blog, we will study how these free space and
fragmentations occur in memory. So, let's get started.
Fragmentation
Fragmentation is an unwanted problem where the memory blocks cannot be allocated to the processes
due to their small size and the blocks remain unused. It can also be understood as when the processes
are loaded and removed from the memory they create free space or hole in the memory and these small
blocks cannot be allocated to new upcoming processes and results in inefficient use of memory. Basically,
there are two types of fragmentation:
 Internal Fragmentation
 External Fragmentation
Internal Fragmentation
In this fragmentation, the process is allocated a memory block of size more than the size of that process.
Due to this some part of the memory is left unused and this cause internal fragmentation.
Example: Suppose there is fixed partitioning (i.e. the memory blocks are of fixed sizes) is used for
memory allocation in RAM. These sizes are 2MB, 4MB, 4MB, 8MB. Some part of this RAM is occupied by
the Operating System (OS).
Now, suppose a process P1 of size 3MB comes and it gets memory block of size 4MB. So, the 1MB that is
free in this block is wasted and this space can’t be utilized for allocating memory to some other process.
This is called internal fragmentation .
How to remove internal fragmentation?
This problem is occurring because we have fixed the sizes of the memory blocks. This problem can be
removed if we use dynamic partitioning for allocating space to the process. In dynamic partitioning, the
process is allocated only that much amount of space which is required by the process. So, there is no
internal fragmentation.
External Fragmentation
In this fragmentation, although we have total space available that is needed by a process still we are not
able to put that process in the memory because that space is not contiguous. This is called external
fragmentation.
Example: Suppose in the above example, if three new processes P2, P3, and P4 come of sizes 2MB, 3MB,
and 6MB respectively. Now, these processes get memory blocks of size 2MB, 4MB and 8MB respectively
allocated.
So, now if we closely analyze this situation then process P3 (unused 1MB)and P4(unused 2MB) are again
causing internal fragmentation. So, a total of 4MB (1MB (due to process P1) + 1MB (due to process P3) +
2MB (due to process P4)) is unused due to internal fragmentation.
Now, suppose a new process of 4 MB comes. Though we have a total space of 4MB still we can’t allocate
this memory to the process. This is called external fragmentation .
How to remove external fragmentation?
This problem is occurring because we are allocating memory continuously to the processes. So, if we
remove this condition external fragmentation can be reduced. This is what done in paging &
segmentation (non-contiguous memory allocation techniques) where memory is allocated non-
contiguously to the processes. We will learn about paging and segmentation in the next blog.
Another way to remove external fragmentation is compaction . When dynamic partitioning is used for
memory allocation then external fragmentation can be reduced by merging all the free memory together
in one large block. This technique is also called defragmentation. This larger block of memory is then
used for allocating space according to the needs of the new processes.

What are Paging and Segmentation?


External fragmentation occurs because we allocate memory continuously to the processes. Due to this
space is left and memory remains unused hence, cause external fragmentation. So to tackle this problem
the concept of paging was introduced where we divide the process into small pages and these pages are
allocated memory non-contiguously into the RAM. So, let’s get started and learn more about it.
Non-Contiguous Memory Allocation Technique
In the non-contiguous memory allocation technique, different parts of the same process are stored in
different places of the main memory. Types:
1. Paging
2. Segmentation
Paging
Paging is a non-contiguous memory allocation technique in which secondary memory and the main
memory is divided into equal size partitions. The partitions of the secondary memory are
called pages while the partitions of the main memory are called frames . They are divided into equal size
partitions to have maximum utilization of the main memory and avoid external fragmentation.
Example: We have a process P having process size as 4B, page size as 1B. Therefore there will we four
pages(say, P0, P1, P2, P3) each of size 1B. Also, when this process goes into the main memory for
execution then depending upon the availability, it may be stored in non-contiguous fashion in the main
memory frame as shown below:
This is how paging is done.
Translation of logical Address into physical Address
As a CPU always generates a logical address and we need a physical address for accessing the main
memory. This mapping is done by the MMU(memory management Unit) with the help of the page table .
Lets first understand some of the basic terms then we will see how this translation is done.
 Logical Address: The logical address consists of two parts page number and page offset.
1. Page Number: It tells the exact page of the process which the CPU wants to access.
2. Page Offset: It tells the exact word on that page which the CPU wants to read.
Logical Address = Page Number + Page Offset
 Physical Address: The physical address consists of two parts frame number and page offset.
1. Frame Number: It tells the exact frame where the page is stored in physical memory.
2. Page Offset: It tells the exact word on that page which the CPU wants to read. It requires no
translation as the page size is the same as the frame size so the place of the word which CPU wants
access will not change.
Physical Address = Frame Number + Page Offset
 Page table: A page stable contains the frame number corresponding to the page number of
some specific process. So, each process will have its own page table. A register called Page Table
Base Register(PTBR) which holds the base value of the page table.
Now, let's see how the translation is done.
How is the translation done?
The CPU generates the logical address which contains the page number and the page offset . The PTBR
register contains the address of the page table. Now, the page table helps in determining the frame
number corresponding to the page number. Now, with the help of frame number and the page offset the
physical address is determined and the page is accessed in the main memory.
Advantages of Paging
1. There is no external fragmentation as it allows us to store the data in a non-contiguous way.
2. Swapping is easy between equal-sized pages and frames.
Disadvantages of Paging
1. As the size of the frame is fixed, so it may suffer from internal fragmentation. It may happen that
the process is too small and it may not acquire the entire frame size.
2. The access time increases because of paging as the main memory has to be now accessed two
times. First, we need to access the page table which is also stored in the main memory and
second, combine the frame number with the page offset and then get the physical address of
the page which is again stored in the main memory.
3. For every process, we have an independent page table and maintaining the page table is extra
overhead.

Segmentation
In paging, we were blindly diving the process into pages of fixed sizes but in segmentation, we divide the
process into modules for better visualization of the process. Here each segment or module consists of the
same type of functions. For example, the main function is included in one segment, library function is
kept in other segments, and so on. As the size of segments may vary, so memory is divided into variable
size parts.
Translation of logical Address into physical Address
As a CPU always generates a logical address and we need a physical address for accessing the main
memory. This mapping is done by the MMU(memory management Unit) with the help of the segment
table .
Lets first understand some of the basic terms then we will see how this translation is done.
 Logical Address: The logical address consists of two parts segment number and page offset.
1. Segment Number: It tells the specific segment of the process from which the CPU wants to read the
data.
2. Segment Offset: It tells the exact word in that segment which the CPU wants to read.
Logical Address = Segment Number + Segment Offset
 Physical Address: The physical address is obtained by adding the base address of the segment
to the segment offset.
 Segment table: A segment table stores the base address of each segment in the main memory.
It has two parts i.e. Base and Limit . Here, base indicates the base address or starting address of
the segment in the main memory. Limit tells the size of that segment. A register called Segment
Table Base Register(STBR) which holds the base value of the segment table. The segment table is
also stored in the main memory itself.

How is the translation done?


The CPU generates the logical address which contains the segment number and the
segment offset . STBR register contains the address of the segment table. Now, the segment table helps
in determining the base address of the segment corresponding to the page number. Now, the segment
offset is compared with the limit corresponding to the Base. If the segment offset is greater than
the limit then it is an invalid address. This is because the CPU is trying to access a word in the segment
and this value is greater than the size of the segment itself which is not possible. If the segment offset is
less than or equal to the limit then only the request is accepted. The physical address is generated by
adding the base address of the segment to the segment offset.
Advantages of Segmentation
1. The size of the segment table is less compared to the size of the page table.
2. There is no internal fragmentation.
Disadvantages of Segmentation
1. When the processes are loaded and removed ( during swapping ) from the main memory then
free memory spaces are broken into smaller pieces and this causes external fragmentation.
2. Here also the time to access the data increases as due to segmentation the main memory has to
be now accessed two times. First, we need to access the segment table which is also stored in
the main memory and second, combine the base address of the segment with the segment
offset and then get the physical address which is again stored in the main memory.

What is Belady’s Anomaly?


As we are increasing the frame number the hit ratio should increase because now more pages of
processes are available in the memory at a time. So, the chances of hits should increase but here the
opposite is happening. The hit ratio is decreasing in place of increasing although we have increased the
frame size. This is called Belady’s Anamoly . This problem comes in FIFO page algorithms. However, this
unusual behavior is only observed sometimes. It doesn't mean that every time the frame size is increased
the page faults will increase.
LRU and Optimal Page Replacement algorithm doesn't suffer from this problem. In these algorithms,
the page faults decrease as the frame size is increased.

What is Virtual Memory and how is it implemented?


We all know that a process is divided into various pages and these pages are used during the execution of
the process. The whole process is stored in the secondary memory. But to make the execution of a
process faster, we use the main memory of the system and store the process pages into it. But there is a
limitation with the main memory. We have limited space and less space in the main memory. So, what if
the size of the process is larger than the size of the main memory? Here, the concept of Virtual Memory
comes into play.
Virtual Memory is a way of using the secondary memory in such a way that it feels like we are using
the main memory.
So, the benefit of using the Virtual Memory is that if we are having some program that is larger than the
size of the main memory then instead of loading all the pages we load some important pages.
In general, when we execute a program, then the entire program is not required to be loaded fully in the
main memory. This is because only a few portions of the program are being executed at a time. For
example, the error handling part of any program is called only when there is some error and we know
that the error happens rarely. So, why to load this part of the program in the main memory and fill the
memory space? Another example can be a large-sized array. Generally, we have over-sized arrays
because we reserve the space for worst-case scenarios. But in reality, only a small part of the array is
used regularly. So, why to put the whole array in the main memory?
So, what we do is we put the frequently used pages of the program in the main memory and this will
result in fast execution of the program because whenever those pages will be needed then it will be
served from the main memory only. Other pages are still in the secondary memory. Now, if some request
to the page that is not in the main memory comes, then this situation is called a Page Miss or Page Fault.
In this situation, we remove one page from the main memory and load the desired page from the
secondary memory to the main memory at the run time i.e swapping of pages will be performed here. By
doing so, the user feels like he/she is having a lot of memory in its system but in reality, we are just
putting that part of the process in the memory that is frequently used. The following figure shows the
working in brief:

In the above image, we can see that the whole process is divided into 6 pages and out of these 6 pages, 2
pages are frequently used and due to this, these 2 pages are put into the physical memory. If there is
some request for the pages present in the physical memory, then it is directly served otherwise if the
page is not present in the physical memory then it is called a page fault and whenever page fault occurs,
then we load the demanded page in the memory and this process is known as Demand Paging.
Demand Paging
Whenever a page fault occurs, then the process of loading the page into the memory is called demand
paging. So, in demand paging, we load the process only when we need it. Initially, when a process comes
into execution, then at that time only those pages are loaded which are required for initial execution of
the process and no other pages are loaded. But with time, when there is a need for other pages, then the
CPU will find that page from the secondary memory and load that page in the main memory.
Following are the steps involved in demand paging:
1. The CPU first tries to find the requested page in the main memory and if it is found then it will
be provided immediately otherwise an interrupt is generated that indicates memory access
fault.
2. Now, the process is sent to the blocked/waiting state because, for the execution of the process,
we need to find the required page from the secondary memory.
3. The logical address of the process will be converted to the physical address because without
having the physical address, you can't locate the page in secondary memory.
4. Now, we apply some page replacement algorithms that can be used to swap the pages from the
main memory to secondary memory and vice-versa.
5. Finally, the page table will be updated with the removal of the address of the old page and the
addition of the address of the new page.
6. At last, the CPU provides the page to the process and the process comes to the running state
from the waiting/block state.
So, in this way, we can implement the concept of Virtual Memory with the help of Demand Paging.

Hardware Synchronization Algorithms : Unlock and Lock, Test


and Set, Swap
Process Synchronization problems occur when two processes running concurrently share the same data
or same variable. The value of that variable may not be updated correctly before its being used by a
second process. Such a condition is known as Race Around Condition. There are a software as well as
hardware solutions to this problem. In this article, we will talk about the most efficient hardware solution
to process synchronization problems and its implementation.
There are three algorithms in the hardware approach of solving Process Synchronization problem:
1. Test and Set
2. Swap
3. Unlock and Lock
Hardware instructions in many operating systems help in the effective solution of critical section
problems.

1. Test and Set:


Here, the shared variable is lock which is initialized to false. TestAndSet(lock) algorithm works in this way
– it always returns whatever value is sent to it and sets lock to true. The first process will enter the critical
section at once as TestAndSet(lock) will return false and it’ll break out of the while loop. The other
processes cannot enter now as lock is set to true and so the while loop continues to be true. Mutual
exclusion is ensured. Once the first process gets out of the critical section, lock is changed to false. So,
now the other processes can enter one by one. Progress is also ensured. However, after the first process,
any process can go in. There is no queue maintained, so any new process that finds the lock to be false
again can enter. So bounded waiting is not ensured.

Test and Set Pseudocode –


//Shared variable lock initialized to false
boolean lock;

boolean TestAndSet (boolean &target){


boolean rv = target;
target = true;
return rv;
}

while(1){
while (TestAndSet(lock));
critical section
lock = false;
remainder section
}

2. Swap:
Swap algorithm is a lot like the TestAndSet algorithm. Instead of directly setting lock to true in the swap
function, key is set to true and then swapped with lock. First process will be executed, and in while(key),
since key=true , swap will take place and hence lock=true and key=false. Again next iteration takes place
while(key) but key=false , so while loop breaks and first process will enter in critical section. Now another
process will try to enter in Critical section, so again key=true and hence while(key) loop will run and swap
takes place so, lock=true and key=true (since lock=true in first process). Again on next iteration while(key)
is true so this will keep on executing and another process will not be able to enter in critical section.
Therefore Mutual exclusion is ensured. Again, out of the critical section, lock is changed to false, so any
process finding it gets t enter the critical section. Progress is ensured. However, again bounded waiting is
not ensured for the very same reason.

Swap Pseudocode –
// Shared variable lock initialized to false
// and individual key initialized to false;

boolean lock;
Individual key;

void swap(boolean &a, boolean &b){


boolean temp = a;
a = b;
b = temp;
}

while (1){
key = true;
while(key)
swap(lock,key);
critical section
lock = false;
remainder section
}

3. Unlock and Lock :


Unlock and Lock Algorithm uses TestAndSet to regulate the value of lock but it adds another value,
waiting[i], for each process which checks whether or not a process has been waiting. A ready queue is
maintained with respect to the process in the critical section. All the processes coming in next are added
to the ready queue with respect to their process number, not necessarily sequentially. Once the ith
process gets out of the critical section, it does not turn lock to false so that any process can avail the
critical section now, which was the problem with the previous algorithms. Instead, it checks if there is any
process waiting in the queue. The queue is taken to be a circular queue. j is considered to be the next
process in line and the while loop checks from jth process to the last process and again from 0 to (i-1)th
process if there is any process waiting to access the critical section. If there is no process waiting then the
lock value is changed to false and any process which comes next can enter the critical section. If there is,
then that process’ waiting value is turned to false, so that the first while loop becomes false and it can
enter the critical section. This ensures bounded waiting. So the problem of process synchronization can
be solved through this algorithm.

Unlock and Lock Pseudocode –


// Shared variable lock initialized to false
// and individual key initialized to false

boolean lock;
Individual key;
Individual waiting[i];

while(1){
waiting[i] = true;
key = true;
while(waiting[i] && key)
key = TestAndSet(lock);
waiting[i] = false;
critical section
j = (i+1) % n;
while(j != i && !waiting[j])
j = (j+1) % n;
if(j == i)
lock = false;
else
waiting[j] = false;
remainder section
}

SEMAPHORES
Semaphores are integer variables that are used to solve the critical section problem by using two atomic
operations, wait and signal that are used for process synchronization.
The definitions of wait and signal are as follows −
 Wait
The wait operation decrements the value of its argument S, if it is positive. If S is negative or zero, then
no operation is performed.
wait(S)
{
while (S<=0);

S--;
}
 Signal
The signal operation increments the value of its argument S.
signal(S)
{
S++;
}

Types of Semaphores
There are two main types of semaphores i.e. counting semaphores and binary semaphores. Details about
these are given as follows −
 Counting Semaphores
These are integer value semaphores and have an unrestricted value domain. These semaphores are used
to coordinate the resource access, where the semaphore count is the number of available resources. If
the resources are added, semaphore count automatically incremented and if the resources are removed,
the count is decremented.
 Binary Semaphores
The binary semaphores are like counting semaphores but their value is restricted to 0 and 1. The wait
operation only works when the semaphore is 1 and the signal operation succeeds when semaphore is 0.
It is sometimes easier to implement binary semaphores than counting semaphores.
Advantages of Semaphores
Some of the advantages of semaphores are as follows −
 Semaphores allow only one process into the critical section. They follow the mutual exclusion
principle strictly and are much more efficient than some other methods of synchronization.
 There is no resource wastage because of busy waiting in semaphores as processor time is not
wasted unnecessarily to check if a condition is fulfilled to allow a process to access the critical
section.
 Semaphores are implemented in the machine independent code of the microkernel. So they are
machine independent.
Disadvantages of Semaphores
Some of the disadvantages of semaphores are as follows −
 Semaphores are complicated so the wait and signal operations must be implemented in the
correct order to prevent deadlocks.
 Semaphores are impractical for last scale use as their use leads to loss of modularity. This
happens because the wait and signal operations prevent the creation of a structured layout for
the system.
 Semaphores may lead to a priority inversion where low priority processes may access the critical
section first and high priority processes later.

1. What is a semaphore in operating systems?


A semaphore is a synchronization tool used to control access to shared resources in operating systems. It
is essentially a variable that regulates access to the shared resource.

2. Why are semaphores used in operating systems?


Semaphores are used to prevent race conditions and ensure that only one process or thread can access
the shared resource at a time. They are used to regulate access to shared resources such as files,
memory, or network connections.

3. What are the different types of semaphores?


There are different types of semaphores such as binary semaphores, counting semaphores, and named
semaphores. Binary semaphores have two states (0 or 1) and are used to control access to a single
resource. Counting semaphores have an integer value and are used to control access to multiple
resources. Named semaphores are used to synchronize processes across different systems.

4. How do semaphores work?


When a process or thread wants to access the shared resource, it must first request the semaphore. If
the semaphore value is greater than zero, the process or thread is allowed to access the shared resource
and the semaphore value is decremented. If the semaphore value is zero, the process or thread must
wait until the semaphore value becomes greater than zero.

5. Can semaphores be used for signaling between processes or threads?


Yes, semaphores can be used for signaling between processes or threads. For example, a process or
thread can signal another process or thread by incrementing the value of a semaphore.

6. What are some common problems that can occur when using semaphores?
Common problems that can occur when using semaphores include deadlocks, priority inversions, and
race conditions. Deadlocks occur when two or more processes or threads are waiting for each other to
release a semaphore. Priority inversions occur when a higher-priority process or thread is blocked by a
lower-priority process or thread holding a semaphore. Race conditions occur when multiple processes or
threads try to access the same shared resource at the same time.

You might also like