R19 Os Unit Iii
R19 Os Unit Iii
Deadlocks - System Model, Deadlocks Characterization, Methods for Handling Deadlocks, Deadlock
Prevention, Deadlock Avoidance, Deadlock Detection, and Recovery from Deadlock; Process
Management and Synchronization - The Critical Section Problem, Synchronization Hardware,
Semaphores, and Classical Problems of Synchronization, Critical Regions, Monitors ; Interprocess
Communication Mechanisms: IPC between processes on a single computer system, IPC between
processes on different systems, using pipes, FIFOs, message queues, shared memory
Introduction
For the purposes of deadlock discussion, a system can be modeled as a collection of limited resources,
which can be partitioned into different categories, to be allocated to a number of processes, each having
different needs.
• Resource categories may include memory, printers, CPUs, open files, tape drives, CD-ROMS,
etc.
• By definition, all the resources within a category are equivalent, and a request of this category
can be equally satisfied by any one of the resources in that category. Some categories may have a
single resource.
• In normal operation a process must request a resource before using it, and release it when it is
done, in the following sequence:
o Request - If the request cannot be immediately granted, then the process must wait until
the resource(s) it needs become available.
o Use - The process uses the resource, e.g. prints to the printer or reads from the file.
o Release - The process relinquishes the resource. so that it becomes available for other
processes. For example, close( ), free( ), delete( ), and release( ).
What is Deadlock?
Deadlock is a common problem in multi-processing where several processes share a specific type of
mutually exclusive resource known as a soft lock or software.
• A set of processes is deadlocked when every process in the set is waiting for a resource that is
currently allocated to another process in the set.
• Deadlock is a situation where a set of processes are blocked because each process is holding a
resource and waiting for another resource acquired by some other process.
Consider an example when two trains are coming toward each other on the same track and there is
only one track, none of the trains can move once they are in front of each other. A similar situation
occurs in operating systems when there are two or more processes that hold some resources and wait
for resources held by other(s). For example, in the below diagram, Process 1 is holding Resource 1
and waiting for resource 2 which is acquired by process 2, and process 2 is waiting for resource 1.
1
Deadlock Characterization
• In a deadlock, processes never finish executing, and system resources are tied up, preventing
other jobs from starting.
A deadlock situation can arise if the following four conditions hold simultaneously in a system:
1. Mutual Exclusion
3. No Preemption
4. Circular Wait
Mutual exclusion: At least one resource must be held in a non-sharable mode; that is, only one process
at a time can use the resource. If another process requests that resource, the requesting process must be
delayed until the resource has been released.
Hold and wait: A process must be holding at least one resource and waiting to acquire additional
resources that are currently being held by other processes.
No preemption: Resources cannot be preempted.; that is, a resource can be released only voluntarily by
the process holding it, after that process has completed its task.
Circular wait: A set {P1, P2, ..., Pn} of waiting processes must exist such that P-0 is waiting for a
resource held by P1, P1 is waiting for a resource held by P2, •••, Pn-1, is waiting for a resource held by
Pn, and P,, is waiting for a resource held by P0.
RESOURCE-ALLOCATION GRAPH
• Deadlocks can be described more precisely in terms of a directed graph called a system resource-
allocation graph.
• The set of vertices V is partitioned into two different types of nodes: P = {P1, P2, ... , Pn}, the set
consisting of all the active processes in the system, and R = {Rl , R2, ... , Rj}, the set consisting of
all resource types in the system.
• A directed edge from process Pi to resource type R; is denoted by Pi à Rj; it signifies that
process Pi has requested an instance of resource type Rj and is currently waiting for that
resource.
• A directed edge from resource type Rj to process Pi is denoted by Rj à Pi; it signifies that an
instance of resource type Rj has been allocated to process Pi.
• Rj as a rectangle. Since resource type Rj may have more than one instance, we represent each
such instance as a dot within the rectangle.
• Note that a request edge points to only the rectangle Rj, whereas an assignment edge must also
designate one of the dots in the rectangle.
2
• When process Pi requests an instance of resource type Rj , a request edge is inserted in the
resource-allocation graph. When this request can be fulfilled, the request edge is instantaneously
transformed to an assignment edge.
• When the process no longer needs access to the resource, it releases the resource; as a result, the
assignment edge is deleted.
Process PI is holding an instance of resource type R2 and is waiting for an instance of resource type R1 .
Process P2 is holding an instance of R1 and an instance of R2 and is waiting for an instance of
R3 .Process P3, is holding an instance of R3.
• Given the definition of a resource-allocation graph, it can be shown that, if the graph contains no
cycles, then no process in the system is deadlocked.
• If the cycle involves only a set of resource types, each of which has only a single instance, then a
deadlock has occurred. Each process involved in the cycle is deadlocked.
• In this case, a cycle in the graph is both a necessary and a sufficient condition for the existence of
deadlock.
• If each resource type has several instances, then a cycle does not necessarily imply that a deadlock
has occurred.
• In this case, a cycle in the graph is a necessary but not a sufficient condition for the existence of
deadlock.
3
Fig: Resource-allocation graph with a cycle but no deadlock.
1. We can use a protocol to prevent or avoid deadlocks, ensuring that the system will never enter a
deadlock state.
2. We can allow the system to enter a deadlock state, detect it, and recover.
3. We can ignore the problem altogether and pretend that deadlocks never occur in the system.
The third solution is the one used by most operating systems, including UNIX and Windows; it is then
up to the application developer to write programs that handle deadlocks. Deadlock prevention provides a
set of methods for ensuring that at least one of the necessary conditions cannot hold. Deadlock
avoidance requires that the operating system be given in advance additional information concerning
which resources a process will request and use during its lifetime. In an environment where a system
does not employ either a deadlock-prevention or a deadlock avoidance algorithm, the system can
provide an algorithm that examines the state of the system to determine whether a deadlock has occurred
and an algorithm to recover from the deadlock. If system is in a deadlocked state yet has no way of
recognizing what has happened. In this case, the undetected deadlock will result in deterioration of the
system's performance.
DEADLOCK PREVENTION:
By ensuring that at least one of those necessary conditions cannot hold, we can prevent the occurrence
of a deadlock.
Mutual Exclusion:
The mutual-exclusion condition must hold for non-sharable resources. For example, a printer
cannot be simultaneously shared by several processes.
Sharable resources, in contrast, do not require mutually exclusive access and thus cannot be
involved in a deadlock. Read-only files are a good example of a sharable resource.
If several processes attempt to open a read-only file at the same time, they can be granted
simultaneous access to the file. A process never needs to wait for a sharable resource.
4
Hold and Wait
To ensure that the hold-and-wait condition never occurs in the system, we must guarantee that,
whenever a process requests a resource, it does not hold any other resources.
One protocol that can be used requires each process to request and be allocated all its resources
before it begins execution.
An alternative protocol allows a process to request resources only when it has none. Before it can
request any additional resources, however it must release all the resources that it is currently
allocated.
To illustrate the difference between these two protocols, we consider a process that copies data
from a DVD drive to a file on disk, sorts the file, and then prints the results to a printer. If all
resources must be requested at the beginning of the process, then the process must initially
request the DVD drive, disk file, and printer.
The second method allows the process to request initially only the DVD drive and disk file. It
copies from the DVD drive to the disk and then releases both the DVD drive and the disk file.
The process must then again request the disk file and the printer. After copying the disk file to
the printer, it releases these two resources and terminates.
First, resource utilization may be low, since resources may be allocated but unused for a long
period.
Second, starvation is possible. A process that needs several popular resources may have to wait
indefinitely, because at least one of the resources that it needs is always allocated to some other
process.
No Preemption
To ensure that this condition does not hold, we can use the following protocol.
If a process is holding some resources and requests another resource that cannot be immediately
allocated to it, then all resources currently being held are preempted. In other words, these
resources are implicitly released.
The preempted resources are added to the list of resources for which the process is waiting.
The process will be restarted only when it can regain its old resources, as well as the new ones
that it is requesting.
Alternatively, if a process requests some resources, we first check whether they are available. If
they are, we allocate them.
If they are not, we check whether they are allocated to some other process that is waiting for
additional resources. If so, we preempt the desired resources from the waiting process and
allocate them to the requesting process.
If the resources are neither available nor held by a waiting process, the requesting process must
wait. While it is waiting, some of its resources may be preempted, but only if another process
requests them.
A process can be restarted only when it is allocated the new resources it is requesting and
recovers any resources that were preempted while it was waiting
5
Circular Wait
One way to ensure that this condition never holds is to impose a total ordering of all resource
types and to require that each process requests resources in an increasing order of enumeration.
To illustrate, we let R = {R1 , R2, ... , Rm} be the set of resource types. We assign to each
resource type a unique integer number, which allows us to compare two resources and to
determine whether one precedes another in our ordering. Formally, we define a one-to-one
function F: R à N, where N is the set of natural numbers.
if the set of resource types R includes tape drives, disk drives, and printers, then the function F
might be defined as follows:
F(tape drive) = 1
F(disk drive) = 5
F(printer) = 12
The protocol to prevent deadlocks is ,Each process can request resources only in an increasing
order of enumeration. That is, a process can initially request any number of instances of a
resource type say,Ri. After that, the process can request instances of resource type Rj if and only
if F(Rj) > F(Ri ).
If several instances of the same resource type are needed, a single request for all of them must be
issued.
For example, a process that wants to use the tape drive and printer at the same time must first
request the tape drive and then request the printer.
Alternatively, we can require that, whenever a process requests an instance of resource type Rj, it
has released any resources Ri such that F(Ri ) >= F(Rj).
If these two protocols are used, then the circular-wait condition cannot hold.
DEADLOCK AVOIDANCE
In the method for avoiding deadlocks is to require additional information about how resources
are to be requested.
With this knowledge of the complete sequence of requests and releases for each process, the
system can decide for each request whether or not the process should wait in order to avoid a
possible future deadlock.
Each request requires that in making this decision the system consider :
A state of the system is called safe if the system can allocate all the resources requested by all
the processes without entering into deadlock. More formally, a system is in a safe state only if
there exists a safe sequence.
A safe state is not a deadlocked state. Conversely, a deadlocked state is an unsafe state. If the
system cannot fulfill the request of all processes then the state of the system is called unsafe.
Not all unsafe states are deadlocks, however an unsafe state may lead to a deadlock.
The various algorithms that use this approach differ in the amount and type of information
required.
6
The simplest and most useful model requires that each process declare the maximum number of
resources of each type that it may need.
Given this a priori information it is possible to construct an algorithm that ensures that the
system will never enter a deadlocked state. Such an algorithm defines the deadlock-avoidance
approach.
The resource-allocation state is defined by the number of available and allocated resources and
the maximum demands of the processes.
An unsafe state will lead to a deadlock. As long as the state is safe, the operating system can
avoid a deadlocked states.
In an unsafe state, the operating system cannot prevent processes from requesting resources such
that a deadlock occurs. The behavior of the processes controls unsafe states.
To illustrate, we consider a system with 12 magnetic tape drives and three processes: P0, P1, and P2 .
Process P0 requires 10 tape drives, process PI may need as many as 4 tape drives, and process P2 may
need up to 9 tape drives. Suppose that, at time to, process P0 is holding 5 tape drives, process PI is
holding 2 tape drives, and process P2 is holding 2 tape drives. Thus, there are 3 free tape drives
remaining
At time to, the system is in a safe state. The sequence PI, P 0, P2 satisfies the safety condition. Process PI
can immediately be allocated all its tape drives and then return them; then process P0 can get all its tape
drives and return them and finally process P2 can get all its tape drives and return them. Finally the
system will have 12 tape drivers available
A system can go from a safe state to an unsafe state. Suppose that, at time t1, process P2 requests and is
allocated one more tape drive. The system is no longer in a safe state. At this point, only process P1 can
be al1ocated all its tape drives. When it returns them, the system will have only 4 available tape drives.
Process P0 is allocated 5 out of 10 , it may request 5 more tape drives. Since they are
unavailable, process Po must wait.
Similarly, process P2 may request an additional 6 tape drives and have to wait, resulting in a
deadlock.
7
Our mistake was in granting the request from process P2 for one more tape drive. If we had
made P2 wait until either of the other processes had finished and released its resources, then we
could have avoided the deadlock.
Given the concept of a safe state, we can define avoidance algorithms that ensure that the system "will
never deadlock. The idea is simply to ensure that the system will always remain in a safe state. Initially
the system is in a safe state. Whenever a process requests a resource that is currently available, the
system must decide whether the resource can be allocated immediately or whether the process must
wait. The request is granted only if the allocation leaves the system in a safe state.
Disadvantage of Safe State and Unsafe State in Deadlock Avoidance is, In this scheme, if a process
requests a resource that is currently available it may still have to wait. Thus resource utilization may be
lower
In addition to the request and assignment edges already described, we introduce a new type of
edge called a claim edge. A claim edge Pi ----> Rj indicates that process Pi may request resource
Rj at some time in the future.
This edge resembles a request edge in direction but is represented in the graph by a dashed line.
When process Pi requests resource Rj, the claim edge Pi à Rj is converted to a request edge.
Similarly, when a resource Rj is released by Pi the assignment edge Rj à Pi is reconverted to a
claim edge Pi àRj
We can allowing a claim edge Pi à Rj to be added to the graph only if all the edges associated
with process Pi are claim edges.
Suppose that process Pi requests resource Rj, The request can be granted only if converting the
request edge Pi à Rj to an assignment edge Rj àPi does not result in the formation of a cycle in
the resource-allocation graph.
If no cycle exists! then the allocation of the resource will leave the system in a safe state. If a
cycle is found then the allocation will put the system in an unsafe state.
Suppose that P1 requests R2 . Although R2 is currently free, we cannot allocate it to P2, since
this action will create a cycle in the graph .
8
Bankers Algorithm
Banker's algorithm is a deadlock avoidance algorithm we use when we are having a resource with
multiple instances. It is named so because this algorithm is used in banking systems to determine
whether a loan can be granted or not. In other words the bank would never allocate its money in
such a way that it can no longer satisfy the needs of all its customers. The bank would try to be in
safe state always.
Some data structures that are used to implement the banker's algorithm are:
1. Available: It is an array of length m. It represents the number of available resources of each type.
If Available[j] = k, then there are k instances available, of resource type Rj.
2. Max: It is an n x m matrix which represents the maximum number of instances of each resource that a
process can request. If Max[i][j] = k, then the process Pi can request at most k instances of resource
type Rj.
3. Allocation: It is an n x m matrix which represents the number of resources of each type currently
allocated to each process. If Allocation[i][j] = k, then process Pi is currently allocated k instances of
resource type Rj.
1. Safety algorithm
Safety Algorithm
A safety algorithm is an algorithm used to find whether or not a system is in its safe state. The algorithm
is as follows:
It means, we need to find an unfinished process whose needs can be satisfied by the available
resources. If no such process exists, just go to step 4.
That means if all processes are finished, then the system is in safe state.
Now the next algorithm is a resource-request algorithm and it is mainly used to determine whether
requests can be safely granted or not.
Let Requesti be the request vector for the process Pi. If Request[i][j]==k, then process Pi wants k
instance of Resource type Rj. When a request for resources is made by the process Pi, the following are
the actions that will be taken:
1. If Requesti <= Needi, then go to step 2; else raise an error condition, since the process has exceeded
its maximum claim.
2. If Requesti <= Availablei then go to step 3; else Pi must have to wait as resources are not available.
3. Now we will assume that resources are assigned to process Pi and thus perform the following steps:
Available= Available-Requesti;
Allocationi=Allocationi +Requesti;
Needi =Needi - Requesti;
If the resulting resource allocation state comes out to be safe, then the transaction is completed and,
process Pi is allocated its resources. But in this case, if the new state is unsafe, then Pi waits for
Requesti, and the old resource-allocation state is restored.
Does not allow the process to change its Maximum need while processing
It allows all requests to be granted in restricted time, but one year is a fixed period for that.
All processes must know and state their maximum resource needs in advance.
10
Example: Consider a system that contains five processes P1, P2, P3, P4, P5 and the three resource types
A, B and C. Following are the resources types: A has 10, B has 5 and the resource type C has 7
instances.
1: The reference of a Need Matrix, Need [i] = Max [i] - Allocation [i], Hence the Need Matrix is
Available Resources of A, B and C are 3, 3, and 2. Now we check if each type of resource request is
available for each process.
11
Step 3: For Process P3:
Available=5, 3, 2 + 2, 1, 1 => 7, 4, 3
Now, we again examine each type of resource request for processes P1 and P3.
7, 5, 5 + 3, 0, 2 => 10, 5, 7
Hence, we execute the banker's algorithm to find the safe state and the safe sequence like P2, P4,
P5, P1 and P3.
3: For granting the Request (1, 0, 2), first we have to check that Request <= Available, that is (1, 0, 2)
<= (3, 3, 2), since the condition is true. So the process P1 gets the request immediately.
DEADLOCK DETECTION
If a system does not employ either a deadlock-prevention or a deadlock avoidance algorithm" then a
deadlock situation may occur. Then in this environment, the system must provide:
An algorithm that examines the state of the system to determine whether a deadlock has
occurred.
12
Deadlock detection can be for systems with only a single instance of each resource type, as well as to
systems with several instances of each resource type. Detection-and-recovery scheme requires overhead
that includes not only the run-time costs of maintaining the necessary information and executing the
detection algorithm but also the potential losses inherent in recovering from a deadlock.
If all resources have only a single instance, then we can define a deadlock detection algorithm that
uses a variant of the resource-allocation graph, called wait for graph.
We obtain this graph from the resource-allocation graph by removing the resource nodes and
collapsing the appropriate edges.
More precisely, an edge from Pi to Pj in a wait-for graph implies that process Pi is waiting for
process Pj to release a resource that Pi needs.
An edge Pi --> Pj exists in a wait-for graph if and only if the corresponding resource allocation
graph contains two edges Pi -> Rq and Rq -> Pj for some resource Rq.
Resource-allocation graph , Corresponding wait-for graph ;If a deadlock exists in the system if and
only if the wait-for graph contains a cycle.
To detect deadlocks, the system needs to maintain the wait-for graph and periodically invoke an
algorithm that searches for a cycle in the graph
The wait-for graph scheme is not applicable to a resource-allocation system with multiple
instances of each resource type.
The wait-for graph scheme is not applicable to a resource-allocation system with multiple instances of
each resource type. The algorithm for Several Instances of a Resource Type employs several time-
varying data structures that are similar to those used in the banker's algorithm.
• Available.
• Allocation.
• Request.
How Deadlock Detection Works
13
Example for Deadlock Detection
To illustrate this algorithm, we consider a system with five processes Po through P4 and three
resource types A, B, and C. Resource type A has 7 instances, resource type B has 2 instances, and
resource type C has 6 instances. Suppose that, at time To, we have the following resource-allocation
state
We claim that the system is not in a deadlocked state. Indeed, if we execute our algorithm, we
will find that the sequence < Po, P2, P3, PI, P4 > results in Finish[i] == true for all i.
Suppose now that process P2 makes one additional request for an instance of type C. The
Request matrix is modified as fo11ows:
We claim that the system is now deadlocked. Although we can reclaim the resources held by
process Po, the number of available resources is not sufficient to fulfill the requests of the other
processes. Thus, a deadlock exists, consisting of processes PI, P2, P3, and P4.
Detection-Algorithm Usage
When should we invoke the detection algorithm? The answer depends on two factors:
If deadlocks occur frequently, then the detection algorithm should be invoked frequently.
In other extreme, we can invoke the deadlock detection algorithm every time a request for
allocation cannot be granted immediately. In this case, we can identify not only the deadlocked
set of processes but also the specific process that "caused" the deadlock.
If the deadlock-detection algorithm is invoked for every resource request, this will incur a
considerable overhead in computation time.
A less expensive alternative is simply to invoke the algorithm at less frequent intervals -for
example, once per hour or whenever CPU utilization drops below 40 percent.
14
RECOVERY FROM DEADLOCK
When a detection algorithm determines that a deadlock exists, several alternatives are available.
One possibility is to inform the operator that a deadlock has occurred and to let the operator
deal, with the deadlock manually.
Another possibility is to let the system recover from the deadlock automatically.
1. One is simply to abort one or more processes to break the circular wait.
2. The other is to preempt some resources from one or more of the deadlocked processes.
Process Termination
To eliminate deadlocks by aborting a process, we use one of two methods. In both methods, the
system reclaims all resources allocated to the terminated processes.
Abort all deadlocked processes. This method clearly will break the deadlock cycle, but at great
expense; the deadlocked processes may have computed for a long time, and the results of these
partial computations must be discarded and probably will have to be recomputed later.
Abort one process at a time until the deadlock cycle is eliminated. This method incurs
considerable overhead, since, after each process is aborted, a deadlock-detection algorithm must
be invoked to determine whether any processes are still deadlocked.
We should abort those processes whose termination will incur the minimum cost. Many factors may
affect which process is chosen, including:
2. How long the process has computed and how much longer the process will compute before
completing its designated task
3. How many and what type of resources the process has used
The other is to preempt some resources from one or more of the deadlocked processes.
Resource Preemption
To eliminate deadlocks using resource preemption, we successively preempt some resources from
processes and give these resources to other processes until the deadlock cycle is broken.If preemption is
required to deal with deadlocks, then three issues need to be addressed:
1. Selecting a victim
2. Rollback
3. Starvation
1: Selecting a victim
Cost factors may include such parameters as the number of resources a deadlocked process is
holding and the amount of time the process has thus far consumed during its execution.
15
2: Rollback
If we preempt a resource from a process, what should be done with that process?
Clearly, it cannot continue with its normal execution; it is missing some needed resource. We
must roll back the process to some safe state and restart it from that state.
Since, in general, it is difficult to determine what a safe state is, the simplest solution is a total
rollback: Abort the process and then restart it.
Although it is more effective to roll back the process only as far as necessary to break the
deadlock, this method requires the system to keep more information about the state of all running
processes.
3: Starvation
How do we ensure that starvation will not occur? That is, how can we guarantee that resources will
not always be preempted from the same process?
In a system where victim selection is based primarily on cost factors, it may happen that the
same process is always picked as a victim. As a result, this process never completes its
designated task, a starvation situation that must be dealt with in any practical system.
Clearly, we must ensure that a process can be picked as a victim only a finite number of times.
The most common solution is to include the number of rollbacks in the cost factor.
***************************************************************************
A cooperating process is one that can affect or be affected by other processes executing in the system.
Cooperating processes can either directly share a logical address space or be allowed to share data only
through files or messages. Concurrent access to shared data may result in data inconsistency. We need
various mechanisms to ensure the orderly execution of cooperating processes that share a logical address
space, so that data consistency is maintained.
Race condition
• A situation, where several processes access and manipulate the same data concurrently and the
outcome of the execution depends on the particular order in which the access takes place, is called a
race condition.
For example if both processes access Counter variable at a time, Producer will update Counter as 6,
where as Consumer Process Update it as 4 which is inconsistent data.
Register1=Counter Register2=Counter
Register1=Register1 +1 Register2=Register2 -1
Counter=Register1 Counter=Register2
• To guard against the race condition, we need to ensure that only one process at a time can be
manipulating the common variable .To make such a guarantee, we require that the processes be
synchronized in some way.
• The important feature of the system is that, when one process is executing in its critical section,
no other process is to be allowed to execute in its critical section. That is, no two processes are
executing in their critical sections at the same time.
• The critical section problem is used to design a set of protocols which can ensure that the Race
condition among the processes will never arise and the processes can use to cooperate.
• Each process must request permission to enter its critical section. The section of code
implementing this request is the entry section. The critical section may be followed by an exit
section. The remaining code is the remainder section.
A solution to the critical-section problem must satisfy the following three requirements:
1. Mutual exclusion. If process Pi is executing in its critical section, then no other processes
can be executing in their critical sections.
2. Progress. If no process is executing in its critical section and some processes wish to enter
their critical sections, then only those processes that are not executing in their remainder
sections can participate in the decision on which will enter its critical section next, and this
selection cannot be postponed indefinitely.
3. Bounded waiting. There exists a bound, or limit, on the number of times that other processes
are allowed to enter their critical sections after a process has made a request to enter its critical
section and before that request is granted.
PETERSON'S SOLUTION
• Peterson's solution is restricted to two processes that alternate execution between their critical
sections and remainder sections.
• The processes are numbered P0 and Pl. For convenience, when presenting Pi, we use Pj to denote
the other process; that is, j equals 1 - i.
• Peterson’s solution addresses the requirements of mutual exclusion, progress and bounded
waiting requirements.
• Peterson's solution requires two data items to be shared between the two processes:
1. int turn;
2. boolean flag[2];
• The variable turn indicates whose turn it is to enter its critical section. That is, if turn == i, then
process Pi is allowed to execute in its critical section.
• The flag array is used to indicate if a process is ready to enter its critical section. For example, if
flag [i] is true, this value indicates that Pi is ready to enter its critical section.
17
The structure of process A in Peterson's solution.
Mutual Exclusion: The method provides mutual exclusion for sure. In entry section, the while
condition involves the criteria for two variables therefore a process cannot enter in the critical
section until the other process is interested and the process is the last one to update turn variable.
Progress: An uninterested process will never stop the other interested process from entering in
the critical section. If the other process is also interested then the process will wait. So progress
met for this solution.
Bounded waiting: However, in Peterson solution, A deadlock can never happen because the
process which first sets the turn variable will enter in the critical section for sure. So bounded
waiting also satisfied by Peterson solution.
Disadvantage
Peterson’s solution works for two processes, but this solution is best scheme in user mode for
critical section.
SYNCHRONIZATION HARDWARE
• Hardware features can make any programming task easier and improve system efficiency. Some
simple hardware instructions that are available on many systems and they can be used effectively
in solving the critical-section problem.
18
• Unfortunately, this solution is not as feasible in a multiprocessor environment. Disabling
interrupts on a multiprocessor can be time consuming, as the message is passed to all the
processors.
• Many modern computer systems therefore provide special hardware instructions that allow us
either to test and modify the content of a word or to swap the contents of two words atomically-
that is, as one uninterruptible unit.
• In general, we can state that any solution to the critical-section problem requires a simple tool-a
lock. Race conditions are prevented by requiring that critical regions be protected by locks.
• That is, a process must acquire a lock before entering a critical section; it releases the lock when
it exits the critical section.
Here Process P1 acquires the lock=0 , checks the condition to false, by the time it setting lock=1 it got
Context switched and control goes to Process P2. Now P2 sense Lock=0 , condition holds false , by
making lock=1 it enters into Critical section. Process P1 resumes and had previous lock=0, so checks the
condition and enters into critical section by making lock=1. Now both the processes are in Critical
Section. So Mutual Exclusion requirement not meeting here
• If we make “while(lock!=0);” and “lock=1” make this as atomic operation we could have
achieved Mutual Exclusion.
19
TEST AND SET INSTRUCTION (HARDWARE SUPPORT)
Lock value = 0 means the critical section is currently vacant and no process is present inside it.
Lock value = 1 means the critical section is currently occupied and a process is present inside it.
• This Function stores the contents of memory location into a variable called “rv” then set the
memory content(target) to 1, returns ‘rv’ value (Previous memory content).
• In order to solve the CSP, When multiple processors execute with this code snippet then the
hardware guarantees that exactly one processor would return value “0”.
20
Working- : This synchronization mechanism works as explained in the following scenes-
Scene-01:
• Process P0 arrives.
• It executes the test-and-set(Lock) instruction.
• Since lock value is set to 0, so it returns value 0 to the while loop and sets the lock value to 1.
• The returned value 0 breaks the while loop condition.
• Process P0 enters the critical section and executes.
• Now, even if process P0 gets preempted in the middle, no other process can enter the critical
section.
• Any other process can enter only after process P0 completes and sets the lock value to 0.
Scene-02:
Scene-03:
• Process P0 comes out of the critical section and sets the lock value to 0.
• The while loop condition breaks.
• Now, process P1 waiting for the critical section enters the critical section.
• Now, even if process P1 gets preempted in the middle, no other process can enter the critical
section.
• Any other process can enter only after process P1 completes and sets the lock value to 0.
Characteristics-
The Intel Systems do not support Test_and_Set Instruction. It Supports “xchg “ instruction which is also
called as The Swap () instruction.
• The Swap () instruction operates on the contents of two words; Like the TestAndSet ()
instruction, it is executed atomically.
• In order to ensure Mutual Exclusion, A global Boolean variable lock is declared and is initialized
to false. In addition, each process has a local Boolean variable key.
21
• Although these algorithms satisfy the mutual-exclusion requirement, they do not satisfy the
bounded-waiting requirement.
SEMAPHORES
• The various hardware-based solutions to the critical-section problem are, like Locks, using the
TestAndSet() and Swap() instructions. These hardware solutions are complicated for application
programmers to use. The design of Hard Ware based solutions can be quite sophisticated.
• The Hardware based solutions are satisfying the two mandatory requirements of Critical section
problem called Mutual Exclusion and Progress. They will not satisfy Bounded Waiting.
• A semaphore S is an integer variable that, apart from initialization, is accessed only through two
standard atomic operations: wait() and signal () .
• The wait () operation was originally termed P (from the Dutch proberen, "to test"); signal() was
originally called V (from verhagen, "to increment").
Semaphores Uses
• A semaphore is an Integer variable, apart from setting initial value, it can be only accessed and
modified by two atopic operations wait () and signal ().
22
• The Initial value of a semaphore will be decided by the kind of application where we are using
semaphore.
1. Process Synchronization
2. In deciding the order in which processes have to be executed
3. In Resource Management.
1. Binary Semaphore.
2. Counting Semaphore.
Binary Semaphore
• The value of a binary semaphore can range only between 0 and 1 then that semaphore is called
binary semaphore.
• On some systems, binary semaphores are known as mutex locks, as they are locks that Provide
mutual exclusion.
• We can use binary semaphores to deal with the critical-section problem for multiple processes.
Counting Semaphores
• The value of a counting semaphore can range over an unrestricted domain. Counting semaphores
can be used to control access to a given resource consisting of a finite number of instances.
• The semaphore is initialized to the number of resources available. Each process that wishes to
use a resource performs a wait ()operation on the semaphore (thereby decrementing the count).
When a process releases a resource, it performs a signal () operation (incrementing the count).
• When the count for the semaphore goes to 0, all resources are being used. After that, processes
that wish to use a resource will block until the count becomes greater than 0.
• For example, consider two concurrently running processes: PI with a statement S1 and P2 with a
statement S2. Suppose we require that S2 be executed only After S1 has completed.
• We can implement this scheme readily by letting PI and P2 share a common semaphore synch,
initialized to 0, and by inserting the statements
23
S1;
wait(synch);
Because synch is initialized to 0, P2 will execute S2 only after PI has invoked signal (synch),
• Suppose if a Resource is having “5 “ Instances and We may use counting semaphore to allocate
these resources among competing Process.
• Here Semaphore will be initialized to 5, The Process wish to get resource performs “wait(s) “
operation on “s”, and while releasing , perform signal(s) operation.
• Simple algorithms require more than one semaphore. This increases the complexity of
semaphore solutions to such algorithms.
• The programmer must keep track of all calls to wait and to signal on the semaphore. If this is not
done in the correct order, programmer error can cause deadlock.
• In the producer-consumer problem, there is one Producer that is producing something and there
is one Consumer that is consuming the products produced by the Producer.
• The producers and consumers share the same memory buffer that is of fixed-size.
• The job of the Producer is to generate the data, put it into the buffer, and again start generating
data. While the job of the Consumer is to consume the data from the buffer.
• The producer should produce data only when the buffer is not full. If the buffer is full, then the
producer shouldn't be allowed to put any data into the buffer.
• The consumer should consume data only when the buffer is not empty. If the buffer is empty,
then the consumer shouldn't be allowed to take any data from the buffer.
• The producer and consumer should not access the buffer at the same time.
24
• "in" used in a producer code represent the next empty buffer
• "out" used in consumer code represent first filled buffer
• “Count” keeps the count number of elements in the buffer
Producer Code
Let's start with the producer who wanted to produce an element " F ", according to code it will enter into
the producer() function, while(1) will always be true, itemP = F will be tried to insert into the buffer,
before that while(count == n); will evaluate to be False.
• Load Rp, m[count] → will copy count value which is 5 to register Rp.
• Suppose just after Increment and before the execution of third line (store m[count], Rp)
25
Consumer Code
Now starting consumer who wanted to consume the first element " A ", according to code it will enter
into the consumer() function, while(1) will always be true, while(count == 0); will evaluate to be
False( since the count is still 5, which is not equal to 0.
Load Rc, m[count] → will copy count value which is 5 to register Rp.
Suppose after this Context Switch occurs back to the leftover part of producer code. . .
Since context switch at producer code was occurred after Increment and before the execution of the third
line (store m[count], Rp) So we resume from, here since Rp holds 6 as incremented value Hence store
m[count], Rp → count = 6
Now the current value of count is 6, which is wrong as Buffer has only 5 elements, this condition is
known as Race Condition and Problem is Producer-Consumer Problem.
The Producer Consumer problem can be solved with the help of semaphores by using three semaphore
variables.
1. Semaphore S: This semaphore variable is used to achieve mutual exclusion between processes. By
using this variable, either Producer or Consumer will be allowed to use or access the shared buffer
at a particular time. This variable is set to 1 initially.
2. Semaphore E: This semaphore variable is used to define the empty space in the buffer. Initially, it
is set to the whole space of the buffer i.e. "n" because the buffer is initially empty.
3. Semaphore F: This semaphore variable is used to define the space that is filled by the producer.
Initially, it is set to "0" because there is no space filled by the producer initially.
26
Pseudo-code for the Producer
• while() is used to produce data, again and again, if it wishes to produce, again and again.
• wait(E) will reduce the value of the semaphore variable "E" by one i.e. when the producer
produces something then there is a decrease in the value of the empty space in the buffer.
• If the buffer is full i.e. the vale of the semaphore variable "E" is "0", then the program will stop
its execution and no production will be done.
• wait(S) is used to set the semaphore variable "S" to "0" so that no other process can enter into the
critical section.
• append() function is used to append the newly produced data in the buffer.
• signal(s) is used to set the semaphore variable "S" to "1" so that other processes can come into
the critical section now because the production is done and the append operation is also done.
• signal(F) is used to increase the semaphore variable "F" by one because after adding the data
into the buffer, one space is filled in the buffer and the variable "F" must be updated.
• while() is used to consume data, again and again, if it wishes to consume, again and again.
• wait(F) is used to decrease the semaphore variable "F" by one because if some data is consumed
by the consumer then the variable "F" must be decreased by one.
• wait(S) is used to set the semaphore variable "S" to "0" so that no other process can enter into the
critical section.
• take() function is used to take the data from the buffer by the consumer.
• signal(S) is used to set the semaphore variable "S" to "1" so that other processes can come into
the critical section now because the consumption is done and the take operation is also done.
• signal(E) is used to increase the semaphore variable "E" by one because after taking the data
from the buffer, one space is freed from the buffer and the variable "E" must be increased.
27
• use() is a function that is used to use the data taken from the buffer by the process to do some
operation.
READERS-WRITERS PROBLEM
• The readers-writers problem is a classical problem of process synchronization, it relates to a file
that is shared between more than one process at a time.
• Among these various processes, some are Readers - which can only read from the file; they do
not perform any updates, some are Writers - can both read and write to a file.
• The readers-writers problem is used for managing synchronization among various reader and
writer process so that there are no problems with the File’s Data, i.e. no inconsistency is
generated.
• Only one writer can be allowed at a time to modify the contents of a file
• When a writer is writing to a file no other reader or writer will be allowed to access a file
28
• Writer can only be allowed to write to a file when they are zero number of readers reading from
the file.
• The solution of readers and writers can be implemented using binary semaphores. We use two
binary semaphores "write" and "mutex", where binary semaphore can be defined as:
• If a writer wishes to access the file, wait operation is performed on write semaphore, which
decrements write to 0 and no other writer can access the file. On completion of the writing job by
the writer who was accessing the file, the signal operation is performed on write.
29
• In the above code of reader, mutex and write are semaphores that have an initial value of 1,
whereas the readcount variable has an initial value as 0.
• Semaphore mutex ensures mutual exclusion and semaphore write handles the writing
mechanism.
• The readcount variable denotes the number of readers accessing the file concurrently. The
moment variable readcount becomes 1, wait operation is used to write semaphore which
decreases the value by one.
• This means that a writer is not allowed to access the file anymore. On completion of the read
operation, readcount is decremented by one.
• When readcount becomes 0, the signal operation which is used to write permits a writer to
access the file.
The dining philosopher's problem is the classical problem of synchronization which says that Five
philosophers are sitting around a circular table and their job is to think and eat alternatively. The dining
philosopher demonstrates a large class of concurrency control problems hence it's a classic
synchronization problem.
• A bowl of noodles is placed at the center of the table along with five chopsticks for each of the
philosophers.
• To eat a philosopher needs both their right and a left chopstick. A philosopher can only eat if
both immediate left and right chopsticks of the philosopher is available.
• In case if both immediate left and right chopsticks of the philosopher are not available then the
philosopher puts down their chopstick and starts thinking again.
30
The five Philosophers are represented as P0, P1, P2, P3, and P4 and five chopsticks by C0, C1,
C2, C3, and C4.
• We use a semaphore to represent a chopstick and this truly acts as a solution of the Dining
Philosophers Problem.
• Wait and Signal operations will be used for the solution of the Dining Philosophers Problem, for
picking a chopstick wait operation can be executed while for releasing a chopstick signal
semaphore can be executed.
• Initially, each element of the semaphore C0, C1, C2, C3, and C4 are initialized to 1 as the
chopsticks are on the table and not picked up by any of the philosophers.
• Let value of i = 0( initial value ), Suppose Philosopher P0 wants to eat, it will enter in
Philosopher() function, and execute Wait( take_chopstickC[i] ); by doing this it holds C0
chopstick and reduces semaphore C0 to 0, after that it execute Wait( take_chopstickC[(i+1) %
5] ); by doing this it holds C1 chopstick and reduces semaphore C1 to 0
• Similarly, suppose now Philosopher P1 wants to eat, it will enter in Philosopher() function, and
execute Wait( take_chopstickC[i] ); by doing this it will try to hold C1 chopstick but will not
be able to do that, since the value of semaphore C1 has already been set to 0 by philosopher P0,
therefore it will enter into an infinite loop.
31
C2 to 0, after that, it executes Wait( take_chopstickC[(i+1) % 5] ); by doing this it holds C3
chopstick and reduces semaphore C3 to 0.
• Hence the above code is providing a solution to the dining philosopher problem, A philosopher
can only eat if both immediate left and right chopsticks of the philosopher are available else
philosopher needs to wait.
• Also at one go two independent philosophers can eat simultaneously i.e., philosopher P0 and P2,
P1 and P3 & P2 and P4 can eat simultaneously as all are the independent processes .
• The solution using semaphores for the dining philosopher problem, we have proved that no two
neighboring philosophers can eat at the same point in time.
• This situation happens if all the philosophers pick their left chopstick at the same time, which
leads to the condition of deadlock and none of the philosophers can eat.
Solution:1
• All the four starting philosophers ( P0, P1, P2, and P3) should pick the left chopstick and then the
right chopstick, whereas the last philosopher P4 should pick the right chopstick and then the left
chopstick.
• This will force P4 to hold his right chopstick first since the right chopstick of P4 is C0, which is
already held by philosopher P0 and its value is set to 0, i.e C0 is already 0, because of which P4
will get trapped into an infinite loop and chopstick C4 remains vacant.
• Hence philosopher P3 has both left C3 and right C4 chopstick available, therefore it will start
eating and will put down its both chopsticks once finishes and let others eat which removes the
problem of deadlock.
Solution:2
• Maximum number of philosophers on the table should not be more than four, in this case,
chopstick C4 will be available for philosopher P3, so P3 will start eating and after the finish of
his eating procedure, he will put down his both the chopstick C3 and C4, i.e. semaphore C3 and
C4 will now be incremented to 1.
• Now philosopher P2 which was holding chopstick C2 will also have chopstick C3 available,
hence similarly, he will put down his chopstick after eating and enable other philosophers to eat.
Solution:3
• A philosopher at an even position should pick the right chopstick and then the left chopstick
while a philosopher at an odd position should pick the left chopstick and then the right chopstick.
Solution:4
• Only in case if both the chopsticks ( left and right ) are available at the same time, only then a
philosopher should be allowed to pick their chopsticks
32
INTRODUCTION TO MONITORS
• Suppose that a process interchanges the order in which the wait (} and signal () operations on the
semaphore mutex are executed, resulting in the following execution:
• In this situation, several processes maybe executing in their critical sections simultaneously,
violating the mutual-exclusion requirement.
• Suppose that a process replaces signal (mutex) with wait (mutex). That is, it executes In this
case, a deadlock will occur.
• Suppose that a process omits the wait (mutex), or the signal (mutex), or both. In this case, either
mutual exclusion is violated or a deadlock will occur.
• To deal with such errors, researchers have developed high-level language synchronization
construct-the monitor type.
33
Fig: Schematic View of Monitor
• All the processes being blocked will form a queue for the Monitor.
Monitors Usage
The monitor is one of the ways to achieve Process synchronization. The monitor is supported by
programming languages to achieve mutual exclusion between processes.
• It is the collection of condition variables and procedures combined together in a special kind of
module or a package.
• The processes running outside the monitor can’t access the internal variable of the monitor but
can call procedures of the monitor.
• If a process is waiting for some reason, that reason might be considered as a conditional variable.
• The Condition variables are used to provide synchronization inside the monitor.
• Only one process can be active in a monitor at a time. If a process wanted to sleep inside the
monitor or allows a waiting process to be resumed, we require conditional variables.
• If one process is accessing a conditional variable, other processes that need to access the
conditional variables in a monitor have to line up in a queue and are only provided access when
the previous process releases the shared variables.
The Operations can be performed over conditional variables are wait() & signal().
• Wait Operation(): If the resource being requested is currently not available, the current process
will be put to sleep. It releases the lock for monitor.
• Signal Operation(): It wakes up a one sleeping process and makes it to resume immediately.
Automatically the lock will be acquired by resumed process.
• A programmer who needs to write a tailor-made synchronization scheme can define one or more
variables of type condition: condition x, y;
• The only operations that can be invoked on a condition variable are wait() and signal ().
• The operation x.wait(); means that the process invoking this operation is suspended until another
process invokes x. signal 0 ;
34
• The x. signal ()operation resumes exactly one suspended process. If no process is suspended,
then the signal() operation has no effect; that is, the state of x is the same as if the operation had
never been executed.
Advantages of Monitor:
• Monitors have the advantage of making parallel programming easier and less error prone than
using techniques such as semaphore.
Disadvantages of Monitor:
• Monitors have to be implemented as part of the programming language . The compiler must
generate code for them.
• This gives the compiler the additional burden of having to know what operating system facilities
are available to control access to critical sections in concurrent processes.
• Monitors alone are not sufficiency to solve this, we need monitors with condition variables to
provide solution to Dining Philosophers Problem.
• Monitor is used to control access to state variables and condition variables. It only tells when to
enter and exit the segment.
• This solution imposes the restriction that a philosopher may pick up her chopsticks only if both
of them are available.
• EATING – When philosopher has got both the forks, i.e., he has entered the section.
• Philosopher i can set the variable state[i] = EATING only if her two neighbors are not eating.
35
Monitor Code
monitor DP
{ //begin of the monitor
status state[5];
condition self[5];
Pickup(int i)
{
state[i] = hungry;
test(i);
if (state[i] != eating)
self[i].wait;
}
Putdown(int i)
{
state[i] = thinking;
test((i + 1) % 5);
test((i + 4) % 5);
}
test(int i)
{
if (state[(i + 1) % 5] != eating
&& state[(i + 4) % 5] != eating
&& state[i] == hungry) {
state[i] = eating;
self[i].signal();
}
}
init()
{
for
i = 0 to 4
state[i] = thinking;
}
} // End of the Monitor
• The distribution of the chopsticks is controlled by the monitor Dining Philosophers. Each
philosopher, before starting to eat, must invoke the operation pickup().
• This act may result in the suspension of the philosopher process. After the successful completion
of the operation, the philosopher may eat.
• Following this, the philosopher invokes the putdown() operation. Thus, philosopher i must
invoke the operations pickup() and putdown() in the following sequence:
• It is easy to show that this solution ensures that no two neighbors are eating simultaneously and
that no deadlocks will occur.
36
INTER PROCESS COMMUNICATION TECHNIQUES
IPC between processes on different systems, using “PIPES”
Pipe is a communication medium between two or more related or interrelated processes. It can
be either within one process or a communication between the child and the parent processes.
Communication can also be multi-level such as communication between the parent, the child
and the grand-child, etc. Communication is achieved by one process writing into the pipe and
other reading from the pipe.
To achieve the pipe system call, create two files, one to write into the file and another to read
from the file.
Pipe mechanism can be viewed with a real-time scenario such as filling water with the pipe into
some container, say a bucket, and someone retrieving it, say with a mug.
The filling process is nothing but writing into the pipe and the reading process is nothing but
retrieving from the pipe.
This implies that one output (water) is input for the other (bucket).
This system call would create a pipe for one-way communication i.e., it creates two descriptors,
first one is connected to read from the pipe and other one is connected to write into the pipe.
Descriptor pipedes[0] is for reading and pipedes[1] is for writing. Whatever is written into
pipedes[1] can be read from pipedes[0].
This call would return zero on success and -1 in case of failure. To know the cause of failure,
check with errno variable or perror() function.
• FIFO Queues are used to achieve unrelated processes communication, the other name for FIFO
Queue is Named Pipes.
• Even though Named Pipes are used for related processes, it gives no meaning to use the named
pipes for related process communication.
• Unlike PIPE, in FIFO Queue we can use single named pipe that can be used for two-way
communication as Named Pipe supports bi-directional communication.
• We use the system call mkfifo () to create a named pipe, which is a kind of a special file.
• A named pipe is much like a traditional pipe, created with the pipe system call. However,
while pipe provides access via two file descriptors, the named pipe is accessed via the file system
at a path.
37
• mkfifo() makes a FIFO special file with the name specified by pathname and the permissions are
specified by mode.
• The advantage is that this FIFO special file can be used by any process for reading or writing just
like a normal file.
• This means to sender process can use the write() system call to write data into the pipe and the
receiver process can use the read() system call to read data from the pipe, hence, completing the
communication.
• On success mkfifo() returns 0 while on error it returns -1. To know the cause of failure, check
with errno variable or perror() function.
• It is same as a pipe except that it is accessed as part of the file system. Multiple process can
access it for writing and reading.
• The FIFO pipe works in blocked mode(by default) i.e., the writing process must be present on
one end while the reading process must be present on the other side at the same time. else the
communication will not happen.
• mkfifo() makes a FIFO special file with name pathname. Here mode specifies the FIFO’s
permissions.
• File mode can also be represented in octal notation such as 0XYZ, where X represents owner, Y
represents group, and Z represents others.
• The value of X, Y or Z can range from 0 to 7. The values for read, write and execute are 4, 2, 1
respectively. If needed in combination of read, write and execute, then add the values
accordingly.
Message Queue:
• Message queues provide an asynchronous communication protocol in which the sender and
receiver of messages don't need to interact at the same time - messages are held in queue until the
recipient retrieves them.
• A message queue is a linked list of messages stored within the kernel and identified by a message
queue identifier message queue is also called as Message broker.
• Message Queue is like a Pipeline, it temporarily holds the messages from sender until receiver
is ready to read them.
• Sender Process inputs the message from tail end to message Queue and Receiving Process
receives the message from Head end of the Message Queue. Basically Messages will follow
FIFO order.
38
• All processes can exchange information through access to a common system message queue.
• The sending process places a message onto a queue which can be read by another process.
• Each message is given an identification or type so that processes can select the appropriate
message.
• Process must share a common key in order to gain access to the queue in the first place.
***********************************************************************
39
Important from Previous Question Papers
1. What is deadlock? What is starvation? How do they differ from each other?(2M)
2. What is a monitor? Explain how dinning philosopher’s problem is solved using monitors with
example pseudo code.(10M)
3. Differentiate between unsafe state and dead lock state.(2M)
4. Discuss readers/writers problem and give solution by using semaphores where readers have priority.
(10M)
5. What is critical section problem?(2M)
6. Define deadlock.(2M)
7. How can deadlock be detected and recovered? Explain in detail with relevant example.(10M)
8. What is a semaphore? Explain how producer-consumer problem is solved using semaphores with
example pseudo code.(10M)
9. What is monitor?(2M)
10. What is a deadlock? Explain the necessary condition for deadlock.(6M)
11. Explain the following deadlock avoidance algorithms i) Banker’s algorithm ii) Safety algorithm.
(8M)
12. Explain the usage and structure of monitors with an example.(6M)
13. Explain Banker's deadlock-avoidance algorithm with an illustration.(8M)
14. Discuss Resource-Request Algorithm with respect to deadlock.(3M)
15. Explain typical elements of inter process communication models.(7M)
16. What is critical section problem? Write and explain Peterson’s solution for it. (7M)
17. How to prevent necessary and sufficient conditions of deadlock? Explain. (7M)
18. What is Resource-Allocation-Graph.(3M)
19. What is a Critical Section problem? Give the conditions that a solution to the critical section
problem must satisfy.(7M)
20. What is a deadlock? How deadlocks are detected?(7M)
THE END
40