OS Module 3 Process Coordination and Deadlock
OS Module 3 Process Coordination and Deadlock
By
Dr. Nileshchandra K. Pikle
Assistant Professor
Vellore Institute of Technology AP
Contents
● Process Synchronization
● Critical Section Problem and Solution
● Semaphores and Monitors
● Classical problems of Process synchronization
● Deadlock Management
● Deadlock Detection
● Deadlock Prevention
● Deadlock Avoidance
● Recovery from Deadlock
2
Process Synchronization
Heap Heap
Data Process
Both processes
P2 attaches
nowSHM
read/write
to its address
at same Data
space
SHM. However SHM still attached to P0
Text Text
4
Shared-Memory Systems
5
A producer Consumer Problem, Issues and Solutions
6
A producer consumer problem
Producer Consumer
7
A producer consumer problem
Computer Printer
Producer Consumer
● A possible solution for this problem would be use of shared memory (buffer)
● To allow producer and consumer concurrently a buffer is added that can be
filled by producer and emptied by consumer
● The print requests from computer will be kept in the shared memory
● Consumer will pick one by one request and prints
9
A producer consumer problem
Computer Printer
10
A producer consumer problem
Consumer may have to wait for new items but the producer can always
produce new items
● Bounded buffer assumes a fixed size buffer
The consumer must wait if buffer is empty and the producer must wait
if the buffer is full
11
A producer consumer problem- Solution 1
Item nextProduced Item nextConsumed
while(true) Producer #define BUFFER_SIZE while(true) Consumer
{ typedef struct{ {
…
/*produce an item in nextProduced*/ while( (in == out)
}item;
while( ( (in + 1)%BUFFER_SIZE ) == out) {
{ item buffer[BUFFER_SIZE]; /*Do Nothing*/
/*Do Nothing*/ int in = 0; }
} int out = 0; nextConsumed = buffer[out] ;
buffer[in] = nextProduced; out = (out + 1)%BUFFER_SIZE;
in = (in + 1)%BUFFER_SIZE /*consume the item in nextConsumed*/
} }
12
A producer consumer problem- Solution 1
Item nextProduced Item nextConsumed
while(true) Producer #define BUFFER_SIZE while(true) Consumer
{ typedef struct{ {
…
/*produce an item in nextProduced*/ while( (in == out)
}item;
while( ( (in + 1)%BUFFER_SIZE ) == out) {
{ item buffer[BUFFER_SIZE]; /*Do Nothing*/
/*Do Nothing*/ int in = 0; }
} int out = 0; nextConsumed = buffer[out] ;
buffer[in] = nextProduced; out = (out + 1)%BUFFER_SIZE;
in = (in + 1)%BUFFER_SIZE /*consume the item in nextConsumed*/
} BUFFER_SIZE = 6 }
in
● Shared buffer implemented as a
circular array with two logical Buffer is empty when in == out
pointers: in and out
● in points to next free position in the Buffer is full when
buffer 0 1 2 3 4 5 ( (in + 1)%BUFFER_SIZE) ) == out
● out points to the first full position in
the buffer 13
out
A producer consumer problem- Solution 1
Item nextProduced Item nextConsumed
while(true) Producer #define BUFFER_SIZE while(true) Consumer
{ typedef struct{ {
…
/*produce an item in nextProduced*/ while( (in == out)
}item;
while( ( (in + 1)%BUFFER_SIZE ) == out) {
{ item buffer[BUFFER_SIZE]; /*Do Nothing*/
/*Do Nothing*/ int in = 0; }
} int out = 0; nextConsumed = buffer[out] ;
buffer[in] = nextProduced; out = (out + 1)%BUFFER_SIZE;
in = (in + 1)%BUFFER_SIZE /*consume the item in nextConsumed*/
} BUFFER_SIZE = 6 }
in in
0 1 2 3 4 5 buffer[ 0 ] = nextProduced;
in = (in+1)%BUFFER_SIZE = (0 + 1)%6
=1 14
out
A producer consumer problem- Solution 1
Item nextProduced Item nextConsumed
while(true) Producer #define BUFFER_SIZE while(true) Consumer
{ typedef struct{ {
…
/*produce an item in nextProduced*/ while( (in == out)
}item;
while( ( (in + 1)%BUFFER_SIZE ) == out) {
{ item buffer[BUFFER_SIZE]; /*Do Nothing*/
/*Do Nothing*/ int in = 0; }
} int out = 0; nextConsumed = buffer[out] ;
buffer[in] = nextProduced; out = (out + 1)%BUFFER_SIZE;
in = (in + 1)%BUFFER_SIZE /*consume the item in nextConsumed*/
} BUFFER_SIZE = 6 }
in in
0 1 2 3 4 5 buffer[ 1 ] = nextProduced;
in = (in+1)%BUFFER_SIZE = (1 + 1)%6
=2 15
out
A producer consumer problem- Solution 1
Item nextProduced Item nextConsumed
while(true) Producer #define BUFFER_SIZE while(true) Consumer
{ typedef struct{ {
…
/*produce an item in nextProduced*/ while( (in == out)
}item;
while( ( (in + 1)%BUFFER_SIZE ) == out) {
{ item buffer[BUFFER_SIZE]; /*Do Nothing*/
/*Do Nothing*/ int in = 0; }
} int out = 0; nextConsumed = buffer[out] ;
buffer[in] = nextProduced; out = (out + 1)%BUFFER_SIZE;
in = (in + 1)%BUFFER_SIZE /*consume the item in nextConsumed*/
} BUFFER_SIZE = 6 }
in in
0 1 2 3 4 5 buffer[ 2 ] = nextProduced;
in = (in+1)%BUFFER_SIZE = (2 + 1)%6
=3 16
out
A producer consumer problem- Solution 1
Item nextProduced Item nextConsumed
while(true) Producer #define BUFFER_SIZE while(true) Consumer
{ typedef struct{ {
…
/*produce an item in nextProduced*/ while( (in == out)
}item;
while( ( (in + 1)%BUFFER_SIZE ) == out) {
{ item buffer[BUFFER_SIZE]; /*Do Nothing*/
/*Do Nothing*/ int in = 0; }
} int out = 0; nextConsumed = buffer[out] ;
buffer[in] = nextProduced; out = (out + 1)%BUFFER_SIZE;
in = (in + 1)%BUFFER_SIZE /*consume the item in nextConsumed*/
} BUFFER_SIZE = 6 }
in in
0 1 2 3 4 5 buffer[ 3 ] = nextProduced;
in = (in+1)%BUFFER_SIZE = (3 + 1)%6
=4 17
out
A producer consumer problem- Solution 1
Item nextProduced Item nextConsumed
while(true) Producer #define BUFFER_SIZE while(true) Consumer
{ typedef struct{ {
…
/*produce an item in nextProduced*/ while( (in == out)
}item;
while( ( (in + 1)%BUFFER_SIZE ) == out) {
{ item buffer[BUFFER_SIZE]; /*Do Nothing*/
/*Do Nothing*/ int in = 0; }
} int out = 0; nextConsumed = buffer[out] ;
buffer[in] = nextProduced; out = (out + 1)%BUFFER_SIZE;
in = (in + 1)%BUFFER_SIZE /*consume the item in nextConsumed*/
} BUFFER_SIZE = 6 }
in in
0 1 2 3 4 5 buffer[ 4 ] = nextProduced;
in = (in+1)%BUFFER_SIZE = (3 + 1)%6
=5 18
out
A producer consumer problem- Solution 1
Item nextProduced Item nextConsumed
while(true) Producer #define BUFFER_SIZE while(true) Consumer
{ typedef struct{ {
…
/*produce an item in nextProduced*/ while( (in == out)
}item;
while( ( (in + 1)%BUFFER_SIZE ) == out) {
{ item buffer[BUFFER_SIZE]; /*Do Nothing*/
/*Do Nothing*/ int in = 0; }
} int out = 0; nextConsumed = buffer[out] ;
buffer[in] = nextProduced; out = (out + 1)%BUFFER_SIZE;
in = (in + 1)%BUFFER_SIZE /*consume the item in nextConsumed*/
} BUFFER_SIZE = 6 }
in in
0 1 2 3 4 5 BUFFER IS FULL
Producer waits till it gets free slot
19
out
A producer consumer problem- Solution 1
Item nextProduced Item nextConsumed
while(true) Producer #define BUFFER_SIZE while(true) Consumer
{ typedef struct{ {
…
/*produce an item in nextProduced*/ while( (in == out)
}item;
while( ( (in + 1)%BUFFER_SIZE ) == out) {
{ item buffer[BUFFER_SIZE]; /*Do Nothing*/
/*Do Nothing*/ int in = 0; }
} int out = 0; nextConsumed = buffer[out] ;
buffer[in] = nextProduced; out = (out + 1)%BUFFER_SIZE;
in = (in + 1)%BUFFER_SIZE /*consume the item in nextConsumed*/
} BUFFER_SIZE = 6 }
in
Check in == out
Consumer wants to consumes an item (5 == 0) = FALSE
0 1 2 3 4 5 nextConsumed = buffer[0]
out = (out + 1)%BUFFER_SIZE
= (0 + 1)%6 20
outout =1
A producer consumer problem- Solution 1
Item nextProduced Item nextConsumed
while(true) Producer #define BUFFER_SIZE while(true) Consumer
{ typedef struct{ {
…
/*produce an item in nextProduced*/ while( (in == out)
}item;
while( ( (in + 1)%BUFFER_SIZE ) == out) {
{ item buffer[BUFFER_SIZE]; /*Do Nothing*/
/*Do Nothing*/ int in = 0; }
} int out = 0; nextConsumed = buffer[out] ;
buffer[in] = nextProduced; out = (out + 1)%BUFFER_SIZE;
in = (in + 1)%BUFFER_SIZE /*consume the item in nextConsumed*/
} BUFFER_SIZE = 6 }
in
Check in == out
Consumer wants to consumes an item (5 == 4) = FALSE
0 1 2 3 4 5 nextConsumed = buffer[4]
out = (out + 1)%BUFFER_SIZE
= (4 + 1)%6 21
outout =5
A producer consumer problem- Solution 1
Item nextProduced Item nextConsumed
while(true) Producer #define BUFFER_SIZE while(true) Consumer
{ typedef struct{ {
…
/*produce an item in nextProduced*/ while( (in == out)
}item;
while( ( (in + 1)%BUFFER_SIZE ) == out) {
{ item buffer[BUFFER_SIZE]; /*Do Nothing*/
/*Do Nothing*/ int in = 0; }
} int out = 0; nextConsumed = buffer[out] ;
buffer[in] = nextProduced; out = (out + 1)%BUFFER_SIZE;
in = (in + 1)%BUFFER_SIZE /*consume the item in nextConsumed*/
} BUFFER_SIZE = 6 }
in
Check in == out
Consumer wants to consumes an item (5 == 5) = TRUE
0 1 2 3 4 5 Buffer is empty
Consumer waits till next item
produced 22
out
A producer consumer problem- Solution 1
Item nextProduced Item nextConsumed
while(true) Producer #define BUFFER_SIZE while(true) Consumer
{ typedef struct{ {
…
/*produce an item in nextProduced*/ while( (in == out)
}item;
while( ( (in + 1)%BUFFER_SIZE ) == out) {
{ item buffer[BUFFER_SIZE]; /*Do Nothing*/
/*Do Nothing*/ int in = 0; }
} int out = 0; nextConsumed = buffer[out] ;
buffer[in] = nextProduced; out = (out + 1)%BUFFER_SIZE;
in = (in + 1)%BUFFER_SIZE /*consume the item in nextConsumed*/
} BUFFER_SIZE = 6 }
in in
24
A producer consumer problem - Solution 2
25
A producer consumer problem- Solution 2
Item nextProduced #define BUFFER_SIZE
Item nextConsumed
while(true) Producer while(true) Consumer
typedef struct{
{ … {
/*produce an item in nextProduced*/ }item; while( count == 0)
while( (counter == BUFFER_SIZE) {
item buffer[BUFFER_SIZE];
{ int in = 0;
/*Do Nothing*/
/*Do Nothing*/ int out = 0; }
} int count = 0; nextConsumed = buffer[out] ;
buffer[in] = nextProduced; out = (out + 1)%BUFFER_SIZE;
in = (in + 1)%BUFFER_SIZE /*consume the item in nextConsumed*/
count++; count– -;
} }
Problem:- Inconsistency when both producer and consumer try to update count
variable
26
A producer consumer problem- Solution 2 issue
Problem:- Inconsistency when both producer and consumer try to update count
variable concurrently
Scenario 1
27
A producer consumer problem- Solution 2 issue
Problem:- Inconsistency when both producer and consumer try to update count
variable concurrently
Scenario 2
Producer Consumer
Producer Consumer
register1 = register1 + 1
register2 6
4
counter = register1
Producer Consumer
counter 5
counter = counter + 1 counter = counter - 1
register1
register1 = counter register2 = counter
37
Critical Section Problem
● Software Solutions
● Hardware Solution
38
A critical section problem
39
A critical section problem
40
A hardware solution to critical section
42
A software solution to critical section
44
Solution to critical section
45
Peterson’s Solution to critical section
do{ int turn do{
boolean flag[2]
flag[i] =True; flag[j] =True;
turn = j; turn = i;
while(flag[j] && turn == j); shared data between Pi and Pj while(flag[i] && turn == i);
Critical Section Critical Section
flag[i] = False; Assumption:- load and store flag[j] = False;
remainder section instructions are atomic i.e. cannot be remainder section
}while(True) }while(True)
interrupted
46
Peterson’s Solution to critical section
do{ int turn do{
boolean flag[2]
flag[i] =True; flag[j] =True;
turn = j; turn = i;
while(flag[j] && turn == j); shared data between Pi and Pj while(flag[i] && turn == i);
Critical Section turn == ji
turn Critical Section
flag[i] = False; flag[j] = False;
flag[i] = True;
False; flag[j] = True;
False;
remainder section remainder section
}while(True) }while(True)
Pi Pj
If both processes try to enter in CS flag values will be true but turn
variable can take only one value either i or j.
● Progress requirement is satisfied as once Pi exits CS it will not control
who will enter in CS
● Bounded wait requirement is also met
50
Peterson’s Solution to critical section
51
Solution to critical section
● Synchronization Hardware
1. TestAndSet
2. Swap
● Mutex Locks
● Semaphores
● Monitor
52
Solution to critical section - Hardware solution
● A critical section problem in uniprocessing
Processes
environment could be solved simply if we could
prevent interrupts from occuring while a shared
P1 P2 P3
variable was being modified.
● That shared memory updates will happen non
preemptively.
CS ● Unfortunately this solution is not feasible in
multiprocessing environment as enabling /disabling
interrupts is time consuming due to message passing
● Message passing delays entry in CS and hence system
C1 C2 C3
efficiency decreases
Processors
}while(TRUE)
54
Solution to critical section - Hardware solution
55
Solution to critical section - Hardware solution
59
1. TestAndSet() instruction with bounded waiting
do{
Key = TRUE
P0 P1 P3 P4
waiting[i] = TRUE;
Lock = FALSE key = TRUE;
P2
while(waiting[i] && key)
Waiting[] = FALSE FALSE FALSE FALSE key = TestAndSet(&Lock);
TRUE
waiting[i] = FALSE
/*Critical Section*/
Let P2 wants to enter in CS j = (i + 1)%n;
waiting[ 2 ] = TRUE while((j != i) && !waiting[j])
Key = TRUE j = (j + 1)%n;
if(j == i)
while(waiting[2] && key)
lock = FALSE;
while loop gets executed till one of the condition is FALSE else
waiting[j] = FALSE;
key = TestAndLock(&Lock); -> This will update Lock value to /*Remainder Section*/
TRUE and Key value to FALSE }while(TRUE)
60
1. TestAndSet() instruction with bounded waiting
do{
Key = FALSE
P0 P1 P3 P4
waiting[i] = TRUE;
Lock = TRUE key = TRUE;
P2
while(waiting[i] && key)
Waiting[] = FALSE FALSE FALSE FALSE key = TestAndSet(&Lock);
TRUE
waiting[i] = FALSE
/*Critical Section*/
● key = TestAndLock(&Lock); -> This will update Lock j = (i + 1)%n;
value to TRUE and Key value to FALSE while((j != i) && !waiting[j])
● Enter into critical section j = (j + 1)%n;
● j = (i + 1) % n -> j = (2+1)%5 = 3 if(j == i)
● while((j!=i) && !waiting[j]) lock = FALSE;
else
j = (j+1)%n;
waiting[j] = FALSE;
- This will find next process willing to enter in CS /*Remainder Section*/
- If no other process willing to enter then P2 will make }while(TRUE)
Lock = FALSE else the P2 will make waiting[j] = FALSE
for jth waiting process
61
2. Swap() instruction
Mutex Lock
Acquire() Release()
{ {
while(!available); /*busy wait*/ available = TRUE;
available = FALSE; }
}
Mutex Lock
do{
Acquire Lock
// Critical Section
This solution results in busy waiting
Release Lock
//Remainder Section
}while(TRUE);
64
Solution to critical section
Semaphore
For example,
integer is a data type that contains all positive and negative integer values.
Operations like addition, subtraction, multiplication, division etc. can be
performed on integer
● Similarly semaphore is a variable that contains integer value and only two
operations Wait() and Signal() can be performed on semaphore variable
66
Solution to critical section
Semaphore
● Semaphore usage:-
- Semaphores can be used to solve various synchronization problems
1. Mutual Exclusion
Synch variable is initialized to 1
wait(Synch)
//Critical Section This can satisfy the mutual exclusion in Critical
Signal(Synch) Section problem
//Remainder Section
67
Solution to critical section
Semaphore
● Semaphore usage:-
- Semaphores can be used to solve various synchronization problems
Binary Semaphore:
1. A Binary Semaphore is a semaphore whose integer value range over 0 and 1.
2. It is nothing, but similar to a lock, with two values: 0 and 1. Here 0 means busy,
while 1 means free.
3. The idea behind using a binary semaphore is that, it allows only one process
at a time to enter the critical section(thus allowing it to access the shared
resource).
4. Here, 0 represents that a process or a thread is in the critical section(i.e. it is
accessing the shared resource), while the other process or thread should
wait for it to complete. On the other hand, 1 means that no process is
accessing the shared resource, and the critical section is free.
69
Solution to critical section
Semaphore Types: Binary and Counting Semaphore
Binary Semaphore:
5. It guarantees mutual exclusion since no two processes can be in the critical
section at any point in time.
70
Solution to critical section
Semaphore Types: Binary and Counting Semaphore
Counting Semaphore:
1. A counting semaphore is a semaphore that has multiple values of the
counter. The value can range over an unrestricted domain.
2. It is a structure, which comprises a variable, known as a semaphore
variable that can take more than two values
3. The value of the semaphore variable is the number of process or thread
that is to be allowed inside the critical section
4. The value of the counting semaphore can range between 0 to N, where N is
the number of the number of process which is free to enter and exit the
critical section.
72
Solution to critical section
Semaphore Types: Binary and Counting Semaphore
Counting Semaphore:
5. As mentioned, a counting semaphore can allow multiple processes or
threads to access the critical section, hence mutual exclusion is not
guaranteed.
6. Since multiple instances of process can access the shared resource at
any time, counting semaphore guarantees bounded wait. Using such a
semaphore, a process which enters the critical section has to wait for
the other process to get inside the critical section, implying that no
process will starve.
73
Solution to critical section
Semaphore Types: Binary and Counting Semaphore
74
Solution to critical section
Semaphore Types: Binary and Counting Semaphore
Code 1: Code 2:
Repeat: Repeat:
P(Mutex) V(Mutex)
// Critical Section // Critical Section
V(Mutex) V(Mutex)
Forever Forever
75
Solution to critical section
Semaphore Types: Binary and Counting Semaphore
Sleep(); wakeup();
}else }else
return; return;
} }
76
Solution to critical section
Semaphore Types: Binary and Counting Semaphore
S.value 31
2 P1 P2 P3 P4 P5 P6
P(S) P(S)
S.queue
CS CS CS CS CS CS
CS Status P1 P2
S.value -1
31
2
0 P1 P2 P3 P4 P5 P6
CS Status P1 P2 P5
S.value -2
-3
-1
31
2
0 P1 P2 P3 P4 P5 P6
CS Status P1 P2 P5
S.value -2
-3
-1
31
2
0 P1 P2 P3 P4 P5 P6
CS Status P1 P2 P5
S.value -3
-2 P1 P2 P3 P4 P5 P6
CS Status P1 P2 P5 P6 V(S)
S.value -2
-1 P1 P2 P3 P4 P5 P6
● P5 performs V(S) and increment S.value ● Before exiting CS, P5 wakeups a process
by 1 lets say P4 from S.queue and leaves CS
82
Solution to critical section
Semaphore Types: Binary and Counting Semaphore
S.value -1
0 P1 P2 P3 P4 P5 P6
● P2 performs V(S) and increment S.value ● Before exiting CS, P2 wakeups a process
by 1 P3 from S.queue and leaves CS
83
Solution to critical section
Semaphore Types: Binary and Counting Semaphore
S.value 01 P1 P2 P3 P4 P5 P6
S.value 21 P1 P2 P3 P4 P5 P6
S.value 2
3 P1 P2 P3 P4 P5 P6
P0 P1 1. P0 executes wait(S)
Wait(S); Wait(Q); 2. P1 executes wait(Q)
Wait(Q); Wait(S); 3. When P0 executes wait(Q) it must wait until P1
. . executes Signal(Q)
. . 4. When P1 executes wait(S) it must wait until P0
. . executes Signal(S)
Signal(S) Signal(Q)
Signal(Q) Signal(S) Since these Signal() operations cannot be executed,
P0 and P1 are deadlocked 87
Problems associated with Semaphore
Starvation
P1 P7 P4 P6
OUT
Low
L L is running on CPU but not in CS
Priority
L
H
Ready Queue
89
Problems associated with Semaphore
Priority Inversion CASE 2
Low
L L L is running on CPU and in CS
Priority
H
L
Ready Queue
90
Problems associated with Semaphore
Priority Inversion CASE 3
Ready Queue
92
Problems associated with Semaphore
Priority Inversion CASE 4
97
Solution to critical section problem - Semaphores
Solution to producer consumer problem using Semaphore
in in
Producer(Item P): Consumer(Item P):
Wait(Empty); Wait(Full);
Wait(S); Wait(S);
Buffer[N] P
0 P1 P
2 3
P 4 5
Buffer[in] = P; Item C = Buffer[out];
in = (in + 1) mod N; out = (out + 1) mod N;
out
Signal(S); Signal(S);
Signal(Full) Empty 2
3 S 01 Full 4
3 Signal(Empty)
98
Solution to critical section problem - Semaphores
Solution to producer consumer problem using Semaphore
in in
Producer(Item P): Consumer(Item P):
Wait(Empty); Wait(Full);
Wait(S); Wait(S);
Buffer[N] P
0 P1 P
2 3
P 4
P 5
Buffer[in] = P; Item C = Buffer[out];
in = (in + 1) mod N; out = (out + 1) mod N;
out
Signal(S); Signal(S);
Signal(Full) Empty 21 S 01 Full 4
5 Signal(Empty)
99
Solution to critical section problem - Semaphores
Solution to producer consumer problem using Semaphore
Producer(Item P): in in Consumer(Item P):
Wait(Empty); Wait(Full);
Wait(S); Wait(S);
Buffer[N] P
0 P1 P
2 3
P 4
P P
5
Buffer[in] = P; Item C = Buffer[out];
in = (in + 1) mod N; out = (out + 1) mod N;
out
Signal(S); Signal(S);
Signal(Full) Empty 01 S 01 Full 5
6 Signal(Empty)
100
Solution to critical section problem - Semaphores
Solution to producer consumer problem using Semaphore
Producer(Item P): in Consumer(Item P):
Wait(Empty); Wait(Full);
Wait(S); Wait(S);
Buffer[N] P
0 P1 P
2 3
P 4
P P
5
Buffer[in] = P; Item C = Buffer[out];
in = (in + 1) mod N; out = (out + 1) mod N;
out
Signal(S); Signal(S);
Signal(Full) Empty 0 S 1 Full 6 Signal(Empty)
101
Solution to critical section problem - Semaphores
Solution to producer consumer problem using Semaphore
Producer(Item P): in Consumer(Item P):
Wait(Empty); Wait(Full);
Wait(S); Wait(S);
Buffer[N] P
0 P1 P
2 3
P 4
P P
5
Buffer[in] = P; Item C = Buffer[out];
in = (in + 1) mod N; out = (out + 1) mod N;
out out
Signal(S); Signal(S);
Signal(Full) Empty 01 S 01 Full 5
6 Signal(Empty)
Now let consumer wants to consume an item P out = (out + 1)mod N = (0 + 1)mpd 6 = 1
Consumer performs Wait(Full) to check if the Consumer release CS by Signal(S)
Buffer is empty or not. Full value becomes 5
Consumer perform Signal(Empty) i.e.
Consumer performs Wait(S) to enter in CS. increase the number of empty slots by 1
Item C = Buffer[0]; 102
Solution to critical section problem - Semaphores
Solution to producer consumer problem using Semaphore
Producer(Item P): in Consumer(Item P):
Wait(Empty); Wait(Full);
Wait(S); Wait(S);
Buffer[N] 0 1 2 3 4 P
5
Buffer[in] = P; Item C = Buffer[out];
in = (in + 1) mod N; out = (out + 1) mod N;
out out
Signal(S); Signal(S);
Signal(Full) Empty 5
6 S 01 Full 01 Signal(Empty)
Similarly consumer consumes item till there is at out = (out + 1)mod N = (5 + 1)mpd 6 = 0
least one item present in the buffer
Consumer release CS by Signal(S)
Consumer performs Wait(Full) to check if the
Buffer is empty or not. Full value becomes 0 Consumer perform Signal(Empty) i.e.
increase the number of empty slots by 1
Consumer performs Wait(S) to enter in CS.
103
Item C = Buffer[5];
Solution to critical section problem - Semaphores
Solution to producer consumer problem using Semaphore
Producer(Item P): in Consumer(Item P):
Wait(Empty); Wait(Full);
Wait(S); Wait(S);
Buffer[N] 0 1 2 3 4 5
Buffer[in] = P; Item C = Buffer[out];
in = (in + 1) mod N; out = (out + 1) mod N;
out
Signal(S); Signal(S);
Signal(Full) Empty 5
6 S 01 Full 01 Signal(Empty)
● If Full semaphore value is 0, it indicates that buffer is empty. So consumer cannot consume item.
This is ensured by Wait(Full) statement of consumer
● If Empty semaphore value is 0, it indicates there is no empty slot available in the buffer or buffer is
Full. So producer cannot produce any item. This is ensured by Wait(Empty) statement of Producer
● Producer and Consumer cannot update Buffer at the same time. This is ensured by Wait(S) statement
of producer and consumer 104
Practice Question 1
Suppose S and Q are the two semaphores initialized to 1. Given P1 and P2 are the
two processes with sharing resources.
P1 P2
Wait(S); Wait(Q); ● Let P1 executes first Wait(S), now S value is 0
● P1 gets preempted and P2 starts execution
Wait(Q); Wait(S); ● P2 executes Wait(Q), now value of Q is 0
● At this point P1 is holding S and P2 is holding Q
Critical Section 1 Critical Section 1
● P2 cannot proceed until P1 Signal(S) and P1 cannot
Signal(S); Signal(Q); proceed until P2 Signal(Q)
● This will result in Deadlock!
Signal(Q); Signal(S);
107
Practice Question 3
Consider following pseudo code, where S is the semaphore initialized to 5 in line #2 and
counter is a shared variable initialized to 0 in line #1. Assume that increment operation in line
#7 is not atomic.
If 5 threads executes the function prop() concurrently, which
1. int counter = 0;
of the following program behaviour(s) is/are possible?
2. Semaphore S = init(5);
3. void prop(void)
1. The value of counter is 5 if all threads executed
4. {
successfully prop()
5. Wait(S);
2. The value of counter is 1 if all threads executed
6. Wait(S);
successfully prop()
7. counter++;
3. The value of counter is 0 if all threads executed
8. Signal(S);
successfully prop()
9. Signal(S);
4. There is deadlock involving all threads
10. }
108
Reader Writer Problem
110
Reader Writer Problem
R R R W W R W W
111
Reader Writer Problem
Reader Writer
readcnt 0 Shared Data
do { do {
wait(mutex);
readcnt++; wait(wrt);
Solution 1:
● A simple solution to this problem is to
represent each fork with semaphore
Semaphore forks[5];
● A philosopher tries to grab the fork by wait()
operation and releases the chopstick by
signal() operation on appropriate
semaphores
● All the elements of forks[] are initialized to 1
114
Dining Philosopher problem
do{
wait(forks[i]);
wait(forks[i+1]);
// Eat
signal(forks[i]);
signal(forks[i+1]);
// Think
}while(TRUE)
Other solutions
116
Problems associated with Semaphore
Summary
Deadlock
Starvation
Priority Inversion
● Solution:- use some high level programming language constructs such as
monitors
117
Solution to critical section problem - Monitors
Monitors
Signal(mutex); Wait(mutex);
Order of wait() and Signal is replaced with
… …
Signal() is changed. wait().
Critical Section Critical Section
Here, several processes This will lead to deadlock
… …
can enter in CS
Wait(mutex) Wait(mutex)
118
Solution to critical section problem - Monitors
Monitor - Syntax
Shared data
Entry Queue
122
DeadLocks
● System model
● Deadlock characterization
● Methods for handling deadlocks
● Deadlock prevention
● Deadlock Avoidance
● Deadlock Detection
● Recovery from deadlock
123
DeadLocks
124
DeadLock example - Traffic Gridlock
Deadlock
125
System Model
Types of resources
1 2
1 2
Computing P1 P1 P2 P4 Pn
3 4 resources
126
System Model
Types of resources
127
System Model
Deadlock Example with Mutex Semaphore
first second
01 01
Process P1 Process P2
Wait(first); Wait(second);
P1 P2
Wait(second); Wait(first);
/* Do some work*/ P1 acquires lock on P2 acquires lock on /* Do some work*/
first second
Signal(second); Signal(first);
P1 is holding lock on P2 is holding lock on
Signal(first); first and requesting second and requesting Signal(second);
for second for first
DEADLOCK! 128
Deadlock characterization
129
Deadlock characterization
Deadlocks can be described more precisely in terms of a directed graph called a System
Resource Allocation Graph.
● This graph consists of a set of vertices V and set of edges E.
● The set of vertices V is partitioned into two different types of nodes
1. P = {P1, P2, P3, …….Pn} the set consisting of all active processes in the system.
2. R = {R1, R2, R3, ……. Rn} the set consisting of all resource types in the system
● A directed edge from process Pi to resource Rj (request edge) is denoted by
Pi -> Rj; It signifies that Pi has requested an instance of resource type Rj
● A directed edge from resource Rj to process Pi (assignment edge) is denoted by
Rj -> P; It signifies that Rj has been allocated to process Pi.
130
Deadlock characterization
Resource instances:
● One instance of resource type R1
● Two instances of resource type R2
P1 P2 P3
● One instance of resource type R3
● Three instances of resource type R4
Process states:
● P1 is holding an instance of R2 and waiting for instance
of type R1
● P2 is holding an instance of R1, R2 and waiting for
R2 instance of R3
● P3 is holding an instance of R3
R4 131
Deadlock characterization
● Given a resource allocation graph, it can be shown that if the graph contains no cycle,
then no process in the system is deadlocked
● If the graph does contain a cycle, then deadlock may exists.
R1
R1 R3
P2
P1 P3
P1 P2 P3
R2 P4
R2
R4
We can deal with the deadlock problem in one of the three ways
Fourth solution is the one used by most OS, including windows and Linux.
It is application developers responsibility to handle deadlock
133
Methods to handle deadlocks
Deadlock Prevention
● For deadlock to occur, each of the four necessary conditions must hold
Mutual exclusion
No preemption
Circular wait.
● By ensuring at least one of these conditions cannot hold, we can prevent the
occurrence of deadlock.
134
Methods to handle deadlocks
Deadlock Prevention - Mutual exclusion
135
Methods to handle deadlocks
Deadlock Prevention - hold and wait
Hold and wait:- To ensure that hold and wait never occurs in the system we must
guarantee that whenever a process requests a resource, it does not hold any
other resources.
136
Methods to handle deadlocks
Deadlock Prevention - hold and wait
Printer 137
Methods to handle deadlocks
Deadlock Prevention - hold and wait
Printer 138
Methods to handle deadlocks
Deadlock Prevention - hold and wait
Protocol 2:- Allocate resources to a process only when it has none. A process may request some
resources and use them, however it must release all currently allocated resources.
DVD HDD
P
COPY
140
Methods to handle deadlocks
Deadlock Prevention - No preemption
141
Methods to handle deadlocks
Deadlock Prevention - Circular wait
142
Methods to handle deadlocks
Deadlock Avoidance
● 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 system will never enter a deadlocked state. Such algorithm
defines the deadlock avoidance approach.
● A deadlock avoidance algorithm dynamically examines the resource allocation
state to ensure that the circular wait condition can never exists.
● The resource allocation state is defined by the number of available and
allocated resources and the maximum demands of the process.
144
Methods to handle deadlocks
Deadlock Avoidance
● Safe state:- A state is safe if the system can allocate resources to each process in
some order and still avoid a deadlock.
● A system is in safe state only if there exists a safe sequence.
● System is in safe state if there exists a sequence <P1, P2, P3, ….. Pn> of all the processes
in the system such that for each Pi the resource that Pi still request can be satisfied by
currently available resources + resources held by all processes Pj with j < i
That is:
1. If Pi resource needs are not immediately available, then Pi can wait until all processes
Pj (j < i) have finished their execution.
2. When they have finished their execution they release all their resources and then Pi
can obtain needed resources, execute, return allocated resources, and terminate
3. When Pi terminates, Pi+1 can obtain needed resources and so on
145
Methods to handle deadlocks
Deadlock Avoidance - Algorithms
● Deadlock avoidance algorithms ensure that a system will never enters into an
unsafe state.
● The deadlock avoidance algorithm depends on resource type - single
instance or multiple instances
● If all resources are of single instance type the a variant of resource allocation
graph can be used
● If resources are of multiple instance type then “Banker’s algorithm” is used
146
Methods to handle deadlocks
Deadlock Avoidance - Resource Allocation Graph Scheme
147
Methods to handle deadlocks
Deadlock Avoidance - Resource Allocation Graph Scheme
Let there are two processes P1 and P2 which need resources R1 and R2
R1
R2
148
Methods to handle deadlocks
Deadlock Avoidance - Resource Allocation Graph Scheme
Let there are two processes P1 and P2 which need resources R1 and R2
R1
● The claim edge from P2 to R2 is changed to
assignment edge
● Now there is a cycle in graph
P1 P2 ● Is the system is in deadlock?
- No. As of now system is in unsafe state and may lead
to deadlock if the claim edge from P1 to R2 changes
R2 to request edge.
149
Methods to handle deadlocks
Deadlock Avoidance - Resource Allocation Graph Scheme
Let there are two processes P1 and P2 which need resources R1 and R2
R2
150
Methods to handle deadlocks
Deadlock Avoidance - Banker’s Algorithm
151
Methods to handle deadlocks
Deadlock Avoidance - Banker’s Algorithm
152
Methods to handle deadlocks
Deadlock Avoidance - Banker’s Algorithm
Safety Algorithm
1. Let work and finish be the vectors of length m and n respectively.
153
Methods to handle deadlocks
Deadlock Avoidance - Banker’s Algorithm
● Considering a system with five processes P0 through P4 and three resources of type A, B, C.
Resource type A has 10 instances, B has 5 instances and type C has 7 instances. Suppose at time
t0 following snapshot of the system has been taken:
P3 2 1 1 4 2 2
P4 0 0 2 5 3 3
155
Methods to handle deadlocks
Deadlock Avoidance - Banker’s Algorithm Example
7 4 3
P0 0 1 0 7 5 3 3 3 2
1 2 2
P1 2 0 0 3 2 2
6 0 0
P2 3 0 2 9 0 2
0 1 1
P3 2 1 1 4 2 2
4 3 1
P4 0 0 2 5 3 3
Total 7 2 5
7 4 3
P0
P0 0 1 0 7 5 3 3 3 2
1 2 2
P1 2 0 0 3 2 2
6 0 0
P2 3 0 2 9 0 2
2 1 1
P3 2 1 1 4 2 2
5 3 1
P4 0 0 2 5 3 3 Sequence
Total 7 2 5
7 4 3
P1
P0 0 1 0 7 5 3 3 3 2
5 3 2 1 2 2
P1 2 0 0 3 2 2
6 0 0
P2 3 0 2 9 0 2
2 1 1 P1
P3 2 1 1 4 2 2
5 3 1
P4 0 0 2 5 3 3 Sequence
Total 7 2 5
7 4 3
P2
P0 0 1 0 7 5 3 3 3 2
5 3 2 1 2 2
P1 2 0 0 3 2 2
6 0 0
P2 3 0 2 9 0 2
2 1 1 P1
P3 2 1 1 4 2 2
5 3 1
P4 0 0 2 5 3 3 Sequence
Total 7 2 5
7 4 3
P3
P0 0 1 0 7 5 3 3 3 2
5 3 2 1 2 2
P1 2 0 0 3 2 2
7 4 3 6 0 0
P2 3 0 2 9 0 2
2 1 1 P1 P3
P3 2 1 1 4 2 2
5 3 1
P4 0 0 2 5 3 3 Sequence
Total 7 2 5
7 4 3
P4
P0 0 1 0 7 5 3 3 3 2
5 3 2 1 2 2
P1 2 0 0 3 2 2
7 4 3 6 0 0
P2 3 0 2 9 0 2
7 4 5 2 1 1 P1 P3 P4
P3 2 1 1 4 2 2
5 3 1
P4 0 0 2 5 3 3 Sequence
Total 7 2 5
7 4 3
P0
P0 0 1 0 7 5 3 3 3 2
5 3 2 1 2 2
P1 2 0 0 3 2 2
7 4 3 6 0 0
P2 3 0 2 9 0 2
7 4 5 2 1 1 P1 P3 P4 P0
P3 2 1 1 4 2 2
7 5 5 5 3 1
P4 0 0 2 5 3 3 Sequence
Total 7 2 5
7 4 3
P2
P0 0 1 0 7 5 3 3 3 2
5 3 2 1 2 2
P1 2 0 0 3 2 2
7 4 3 6 0 0
P2 3 0 2 9 0 2
7 4 5 2 1 1 P1 P3 P4 P0 P2
P3 2 1 1 4 2 2
7 5 5 5 3 1
P4 0 0 2 5 3 3 Sequence
Total 7 2 5
7 4 3
P2
P0 0 1 0 7 5 3 3 3 2
5 3 2 1 2 2
P1 2 0 0 3 2 2
7 4 3 6 0 0
P2 3 0 2 9 0 2
7 4 5 2 1 1 P1 P3 P4 P0 P2
P3 2 1 1 4 2 2
7 5 5 5 3 1
P4 0 0 2 5 3 3 Sequence
Total 7 2 5
If atleast one process request cannot be satisfied the system May lead to deadlock. That means
safe sequence is not possible.
164
Deadlock
Practice Question 1
An operating system uses the Banker’s algorithm for deadlock avoidance when managing the
allocation of three resource types X, Y, and Z to three processes P0, P1, and P2. The table given below
presents the current system state. Here, the Allocation matrix shows the current number of resources
of each type allocated to each process and the Max matrix shows the maximum number of resources
of each type required by each process during its execution. There are 3 units of type X, 2 units of type Y
and 2 units of type Z still available. The system is currently in a safe state. Consider the following independent
requests for additional resources in the current state:
165
Deadlock
Practice Question 2
Q. 1 A system contains three programs and each requires three tape units for its
operation. The minimum number of tape units which the system must have such that
deadlocks never arise is.
If 6 resources are there then it may be possible that all three process have 2 resources and waiting for 1 more
resource. Therefore, all of them will have to wait indefinitely. If 7 resources are there, then atleast one must have 3
resources so deadlock can never occur.
Q. 2 A system has 6 identical resources and N processes competing for them. Each process can request at most 2
resources. Which one of the following values of N could lead to a deadlock?
166
Deadlock
Practice Question 2
Consider a non-negative counting semaphore S. The operation P(S) decrements S, and V(S)
increments S. During an execution, 20 P(S) operations and 12 V(S) operations are issued in
some order. The largest initial value of S
for which at least one P(S) operation will remain blocked is _____________ .
Ans: 7
S is initialized to 7 and if 12 V(S) operations performed then value of S becomes 19. Now 20
processes will try to perform P(S) but only 19 will complete and last will be blocked.
167