Professional Documents
Culture Documents
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.
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?
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.
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 .
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.
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.
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.
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.
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
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
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:
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.
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.
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.
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.
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?
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.
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.
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.
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.
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;
while (1){
key = true;
while(key)
swap(lock,key);
critical section
lock = false;
remainder section
}
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.
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.