Unit III Final
Unit III Final
deadlocks
Mr. S. C. Sagare
Introduction
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 (that is,
both code and data) or be allowed to share data only through files or messages.
One process may only partially complete execution before another process is
scheduled.
In fact, a process may be interrupted at any point in its instruction stream, and
the processing core may be assigned to execute instructions of another process
• The code for the producer process can be modified as follows:
• Although the producer and consumer routines shown above are correct separately,
they may not function correctly when executed concurrently.
Suppose that the value of the variable counter is currently 5 and that the producer and
consumer processes concurrently execute the statements “counter++” and
“counter--”.
Following the execution of these two statements, the value of the variable counter may
be 4, 5, or 6!
The only correct result, though, is counter == 5, which is generated correctly if the
producer and consumer execute separately.
We can show that the value of counter may be incorrect as follows. Note that the
statement “counter++” may be implemented in machine language (on a typical
machine) as follows:
register1 = counter
register1 = register1 + 1
counter = register1
where register1 is one of the local CPU registers. Similarly, the statement “counter--” is
implemented as follows:
register2 = counter
register2 = register2 − 1
counter = register2
where again register2 is one of the local CPU registers. Even though register1 and
register2 may be the same physical register (an accumulator, say), remember that the
contents of this register will be saved and restored by the interrupt handler
The concurrent execution of “counter++” and “counter--” is equivalent to a
sequential execution in which the lower-level statements presented
previously are interleaved in some arbitrary order (but the order within each
high-level statement is preserved). One such interleaving is the following:
T0: producer execute register1 = counter {register1 = 5}
T1: producer execute register1 = register1 + 1 {register1 = 6}
T2: consumer execute register2 = counter {register2 = 5}
T3: consumer execute register2 = register2 − 1 {register2 = 4}
T4: producer execute counter = register1 {counter = 6}
T5: consumer execute counter = register2 {counter = 4}
Notice that we have arrived at the incorrect state “counter == 4”, indicating
that four buffers are full, when, in fact, five buffers are full.
If we reversed the order of the statements at T4 and T5, we would arrive at
the incorrect state “counter == 6”.
We would arrive at this incorrect state because we allowed both processes
to manipulate the variable counter concurrently.
A situation like this, 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.
Process Synchronization means sharing system resources by processes in a such
a way that, Concurrent access to shared data is handled thereby minimizing the
chance of inconsistent data.
Each process has a segment of code, called a critical section, in which the process
may be changing common variables, updating a table, writing a file, and so on.
The important feature of the system is that, when one process is executing in
its critical section, no other process is 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 to design a protocol that the processes can
use to cooperate.
Bounded waiting. After a process makes a request for getting into its critical
section, there is a limit for how many other processes can get into their critical
section, before this process's request is granted. So after the limit is reached,
system must grant the process permission to get into its critical section..
Peterson’s Solution
A classic software-based solution to the critical-section problem known as
Peterson’s solution.
The processes are numbered P0 and P1. For convenience, when presenting Pi , we
use Pj to denote the other process; that is, j equals 1 − i.
int turn :The process whose turn is to enter the critical section.
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.
Peterson’s Solution preserves all three conditions :
Mutual Exclusion is assured as only one process can access the critical
section at any time.
Progress is also assured, as a process outside the critical section does not
blocks other processes from entering the critical section.
To prove property 1, we note that each Pi enters its critical section only if either
flag[j] == false or turn == i.
To prove properties 2 and 3,we note that a process Pi can be prevented from
entering the critical section only if it is stuck in the while loop with the
condition flag[j] == true and turn == j; this loop is the only one possible.
If Pj is not ready to enter the critical section, then flag[j] == false, and Pi can enter
its critical section.
Mutex and Mutex Locks
operating-systems designers build software tools to solve the critical-section
problem.The simplest of these tools is the mutex lock.
After that, any thread needing the resource must use the mutex to lock the
resource from other threads while it is using the resource.
If the mutex is already locked, a thread needing the resource is typically queued
by the system and then given control when the mutex becomes unlocked
We use the mutex lock to protect critical regions and thus prevent race
conditions.
That is, a process must acquire the lock before entering a critical section
it releases the lock when it exits the critical section. The acquire()function
acquires the lock, and the release() function releases the lock.
A mutex lock has a Boolean variable available whose value indicates if the lock is
available or not.
If the lock is available, a call to acquire() succeeds, and the lock is then considered
unavailable.
While a process is in its critical section, any other process that tries
to enter its critical section must loop continuously in the call to acquire().
Semaphores
In 1965, Dijkstra proposed a new and very significant technique for managing concurrent processes
by using the value of a simple integer variable to synchronize the progress of interacting processes.
Semaphore is nothing but a synchronization tool with the help of which we can ensure that the
critical section can be accessed by the processes in a mutually exclusive manner.
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 verhogen,“to increment”).
The definition of wait() is as follows:
wait(S) {
while (S <=0) ; // busy wait
S--;
}
Wait() :-- it is called when a process wants to access a resource. ( when the
semaphore variable is negative, the process wait is blocked.
Now if suppose P1 enters in its critical section then the value of semaphore s
becomes 0.
Now if P2 wants to enter its critical section then it will wait until s > 0, this can
only happen when P1 finishes its critical section and calls V operation on
semaphore s.
When a process executes the wait() operation and finds that the semaphore
value is not positive, it must wait.
However, rather than engaging in busy waiting, the process can block itself.
The block operation places a process into a waiting queue associated with the
semaphore, and the state of the process is switched to the waiting state.
Indefinite blocking may occur if we remove processes from the list associated
with a semaphore in LIFO (last-in, first-out) order.
Priority Inversion
A scheduling challenge arises when a higher-priority process needs to read or
modify kernel data that are currently being accessed by a lower-priority process—
or a chain of lower-priority processes.This problem is called priority inversion
Priority inversion is the condition where high priority process need to wait for low
priority process to release the resource.
Since kernel data are typically protected with a lock, the higher-priority process will
have to wait for a lower-priority one to finish with the resource.
Assume that process H requires resource R, which is currently being accessed by process
L. Ordinarily, process H would wait for L to finish using resource R.
However, now suppose that process M becomes runnable, thereby preempting process
L.
Indirectly, a process with a lower priority—process M—has affected how long process
H must wait for L to relinquish resource R.
This problem is known as priority inversion.
Processes Pi and Pj now wait for each other indefinitely. Because a high-priority
process waits for a process with a low priority, this situation is called priority
inversion
Three scenario's of normal execution
1.
--L is running but not in CS.
--If H wish to execute then it will preempt L and execute
2.
--L is running in CS.
--If H wish to execute but not in CS then it will preempt L and execute
3.
--L is running in CS.
--If H wish to execute in CS then H has to wait for L and then execute
Example,
L,M,H
L is executing in CS.
H wish to execute in CS.
M interrupts L and start execution…
Sequence of execution..
L-M-L-H
Classic Problems of Synchronization
A solution to a process synchronization problem should meet three important
criteria.
critical sections and signaling are the key elements of process synchronization, so
a solution to a process synchronization problem should incorporate a suitable
combination of these elements.
The Bounded-Buffer Problem
A producers–consumers system with bounded buffers consists of an unspecified
number of producer and consumer processes and a finite pool of buffers.
However, if a writer and some other process (either a reader or a writer) access
the database simultaneously, disorder may ensue.
To ensure that these difficulties do not arise, we require that the writers have
exclusive access to the shared database while writing to the database. This
synchronization problem is referred to as the readers–writers problem
The Readers–Writers Problem
The readers–writers problem has several variations, all involving priorities.
The simplest one, referred to as the first readers–writers problem, requires that
no reader be kept waiting unless a writer has already obtained permission to use
the shared object.
In other words, no reader should wait for other readers to finish simply because
a writer is waiting.
The second readers–writers problem requires that, once a writer is ready, that
writer perform its write as soon as possible.
In other words, if a writer is waiting to access the object, no new readers may
start reading.
A solution to either problem may result in starvation.
In the first case, writers may starve; in the second case, readers may starve.
For this reason, other variants of the problem have been proposed.
The Dining-Philosophers Problem
Consider five philosophers who spend their lives thinking and eating.
The philosophers share a circular table surrounded by five chairs, each belonging
to one philosopher.
In the center of the table is a bowl of rice, and the table is laid with five single
chopsticks
When a philosopher thinks, she does not interact with her colleagues.
From time to time, a philosopher gets hungry and tries to pick up the two
chopsticks that are closest to her (the chopsticks that are between her left and
right neighbors).
When a hungry philosopher has both her chopsticks at the same time, she eats
without releasing the chopsticks.
When she is finished eating, she puts down both chopsticks and starts thinking
again.
One simple solution is to represent each chopstick with a semaphore.
A philosopher tries to grab a chopstick by executing a wait() operation on that
semaphore.
She releases her chopsticks by executing the signal() operation on the
appropriate semaphores.Thus, the shared data are
semaphore chopstick[5];
Deadlocks
In a multiprogramming environment, several processes may compete for a finite
number of resources.
A process requests resources; if the resources are not available at that time, the
process enters a waiting state.
Sometimes, a waiting process is never again able to change state, because the
resources it has requested are held by other waiting processes.
CPU cycles, files, and I/O devices (such as printers and DVD
drives) are examples of resource types.
A set of blocked processes each holding a resource and waiting to acquire a
resource held by another process in the set.
• The resources may be either physical (I/O devices, tape drives, memory space,
and CPU cycles) or logical (files and semaphores).
• A process must request a resource before using it, and must release the
resource after using it
Under the normal mode of operation, a process may utilize a resource in only
the following sequence:
2. Use.
The process can operate on the resource (for example, if the resource is a
printer, the process can print on the printer).
3. Release.
The process releases the resource.
Deadlock Characterization
In a deadlock, processes never finish executing, and system resources
are tied up, preventing other jobs from starting.
2. 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.
4. Circular wait. A set {P0, P1, ..., Pn} of waiting processes must exist such that P0
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 Pn 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.
P = {P1, P2, ..., Pn}, the set consisting of all the active processes in the system, and
R = {R1, R2, ..., Rm}, the set consisting of all resource types in the system.
It signifies that an instance of resource type Rj has been allocated to process Pi.
Since resource type Rj may have more than one instance, each such instance is
represented 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.
When process Pi requests an instance of resource type Rj, a request edge is inserted
in the resource-allocation graph.
When the process no longer needs access to the resource, it releases the
resource.
Resource allocation graph
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 graph does contain a cycle, then a deadlock may exist.
If each resource type has exactly one instance, then a cycle implies that a
deadlock has occurred.
If the cycle involves only a set of resource types, each of which has only a
single instance, then a deadlock has occurred
Methods for Handling Deadlocks
We can deal with the deadlock problem in one of three ways:
•We can use a protocol to prevent or avoid deadlocks, ensuring that the system will
never enter a deadlocked state.
• We can allow the system to enter a deadlocked state, detect it, and recover.
• We can ignore the problem altogether and pretend that deadlocks never occur in
the system.
To ensure that deadlocks never occur, the system can use either a deadlock
prevention or a deadlock-avoidance scheme.
Mutual Exclusion
We need to the categorization of all the resources in sharable and non sharable.
The mutual exclusion condition must hold.
Shared resources such as read-only files do not lead to deadlocks.
Unfortunately some resources, such as printers and tape drives, require exclusive
access by a single process.
To ensure that this condition does not hold, we can use the following protocol.
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.
Circular Wait
To ensure that the circular-wait condition never holds is to determine a total
ordering of all resource types, and to require that each process requests
resources in an increasing order of enumeration.
– Example: Let R={R1, R2, …, Rm} be the set of resource types.
F(tape drive)= 1;
F(disk drive)= 5;
F(Printer)= 12.
A protocol to prevent deadlocks: Each process can request
resources only in an increasing order of enumeration.
The limits ensure that at least one of the necessary conditions for deadlock
cannot occur. Possible side effects of preventing deadlocks by this method,
however, are low device utilization and reduced system throughput.
For example, in a system with one tape drive and one printer, the system might
need to know that process P will request first the tape drive and then the printer
before releasing both resources, whereas process Q will request first the printer
and then the tape drive.
Here the operating system should have a prior database regarding the
availability of the resources, occupancy of resources, need of the processes.
Safe State
A state is safe if the system can allocate resources to each process in some order
and still avoid a deadlock.
More formally, a system is in a safe state only if there exists a safe sequence.
If Pi resource needs are not immediately available, then Pi can wait until all Pj
have finished
When Pj is finished, Pi can obtain needed resources, execute, return allocated
resources, and terminate
When Pi terminates, Pi +1 can obtain its needed resources, and so on
Not all unsafe states are deadlocks, however An unsafe state may lead
to a deadlock
As long as the state is safe, the operating system can avoid unsafe (and
deadlocked) states.
Basic fact:
If a system is in safe state no deadlocks
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
allocated all its tape drives.
When it returns them, the system will have only four available tape drives.
Since process P0 is allocated five tape drives but has a maximum of ten, it may
request five more tape drives.
Similarly, process P2 may request six additional tape drives and have to wait,
resulting in a deadlock.
Bank transaction example
In addition to the request and assignment edges, 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 actually requests resource Rj, the claim edge Pi → Rj is converted to a
request edge.
Note that the resources must be claimed a priori in the system. That is, before process
Pi starts executing, all its claim edges must already appear in the resource-allocation graph.
Resource-Allocation-Graph Algorithm
Now 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.
We check for safety by using a cycle-detection algorithm.
An algorithm for detecting a cycle in this graph requires an
order of n2 operations, where n = number of processes in the
system.
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. In that case, process Pi will have to wait for its
requests to be satisfied.
Banker’s Algorithm
The resource-allocation-graph algorithm is not applicable to a resource allocation
system with multiple instances of each resource type.
The name was chosen because the algorithm could be used in a banking system
to ensure that the bank never allocated its available cash in such a way that it
could no longer satisfy the needs of all its customers.
When a new process enters the system, it must declare the maximum number of
instances of each resource type that it may need.
This number may not exceed the total number of resources in the system
When a user requests a set of resources, the system must determine whether
the allocation of these resources will leave the system in a safe state.
If it will, the resources are allocated; otherwise, the process must wait until
some other process releases enough resources.
Bankers’s Algorithm is resource allocation and deadlock avoidance algorithm
which test all the request made by processes for resources, it check for safe
state, if after granting request system remains in the safe state it allows the
request and if their is no safe state it don’t allow the request made by the
process.
1. If request made by process is less than equal to max need to that process.
2. If request made by process is less than equal to freely available resource in
the system.
Several data structures must be maintained to implement the banker’s
algorithm.
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.
Several Instances of a Resource Type
The wait-for graph scheme is not applicable to a resource-allocation system with
multiple instances of each resource type.