0% found this document useful (0 votes)
50 views167 pages

OS Module 3 Process Coordination and Deadlock

The document discusses process synchronization and deadlocks in operating systems, including how cooperating processes require mechanisms for interprocess communication like shared memory and message passing. It describes the classical producer-consumer problem and solutions using a shared buffer to allow a producer and consumer to work concurrently without interfering with each other. The solution uses pointers and modulo arithmetic to implement a circular buffer in shared memory that the producer and consumer can use to exchange items in a synchronized way.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
50 views167 pages

OS Module 3 Process Coordination and Deadlock

The document discusses process synchronization and deadlocks in operating systems, including how cooperating processes require mechanisms for interprocess communication like shared memory and message passing. It describes the classical producer-consumer problem and solutions using a shared buffer to allow a producer and consumer to work concurrently without interfering with each other. The solution uses pointers and modulo arithmetic to implement a circular buffer in shared memory that the producer and consumer can use to exchange items in a synchronized way.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 167

Operating System

Process Synchronization 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

● Processes executing concurrently in operating system may be


independent processes or cooperating processes
● A process is cooperating if it can affect or be affected by other
processes executing in the system
● Any process that shares resources with other processes is
cooperating process
● Cooperating processes require an Interprocess Communication (IPC)
mechanism that will allow them to exchange data and information
● IPC models for interprocess communication
1. Shared Memory
2. Message Passing
3
Shared-Memory Systems
Stack Shared memory created by P1 allocated in Stack
P1’s address space
SHM SHM

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

P1 Two processes in the system P2

4
Shared-Memory Systems

● Normally OS prevents a process trying to access address space of


other processes
● Shared memory requires that two processes agrees to remove this
restriction
● The information is exchanged between processes by reading/writing
data in the shared areas.
● Processes must ensure that they are not writing to the same location
simultaneously.
● OS does not handle the problem of race conditions

5
A producer Consumer Problem, Issues and Solutions

6
A producer consumer problem
Producer Consumer

● A producer produces the item that is consumed by consumer


● What if producer produces at higher rate than a consumer can consume?
● What if consumer consumes at higher rate than a producer can produce?

7
A producer consumer problem
Computer Printer

Producer Consumer

● Both producer (computer) and consumer (printer) running concurrently


● Computer can send multiple print request
● Printer can print only one document at a time
● If computer sends request while printer is busy then request gets lost
● Computer must wait till printer gets free before sending print request
8
A producer consumer problem
Computer Printer

Producer Shared Memory (buffer) 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

Producer Shared Memory (buffer) Consumer

● Producer and consumer must be synchronized so that the consumer does


not try to consume an item that has not yet been produced

10
A producer consumer problem

● Buffer can be bounded or unbounded


● In case of unbounded buffer there is no practical limit on the size of the
buffer.

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

Check ((in + 1)%BUFFER_SIZE ) == out


Let producer wants to produce an item ((0 + 1)%6 == 0) = FALSE

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

Check ((in + 1)%BUFFER_SIZE ) == out


Let producer wants to produce an item ((1 + 1)%6 == 0) = FALSE

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

Check ((in + 1)%BUFFER_SIZE ) == out


Let producer wants to produce an item ((2 + 1)%6 == 0) = FALSE

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

Check ((in + 1)%BUFFER_SIZE ) == out


Let producer wants to produce an item ((3 + 1)%6 == 0) = FALSE

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

Check ((in + 1)%BUFFER_SIZE ) == out


Let producer wants to produce an item ((4 + 1)%6 == 0) = FALSE

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

Check ((in + 1)%BUFFER_SIZE ) == out


Let producer wants to produce an item ((5 + 1)%6 == 0) = TRUE

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

Check (in + 1)%BUFFER_SIZE ) == out)


Producer wants to produce an item ((5+1)%6 == 5) = FALSE
buffer[5] = nextProduced
0 1 2 3 4 5
in = (in + 1)%BUFFER_SIZE
= (5+1)%6 23
=0
out
A producer consumer problem solution 1 issue

● Above solution works fine for both producer and consumer


● However the solution uses only BUFFER_SIZE-1 elements
● There is a solution that fills all the buffers in the same way but
algorithm becomes very complex
● Another solution use a shared variable ‘counter’ to control access to
shared resources

24
A producer consumer problem - Solution 2

● A shared variable counter is initialized to 0


● Counter is incremented every time we add a new item to buffer
● Counter is decremented every time we remove one item to buffer
● This way we can use complete BUFFER_SIZE

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

Let's assume initially count value is 5 count 5


1. Consumer executes the count - -
statement
What will be
2. Producer executes the count++ the value of
statement count?

27
A producer consumer problem- Solution 2 issue
Problem:- Inconsistency when both producer and consumer try to update count
variable concurrently
Scenario 2

Let's assume initially count value is 5 count 5


1. Producer executes the count++
statement
What will be
2. Consumer executes the count—
the value of
statement count?

In both cases expected output is 5


28
A producer consumer problem- Solution 2 issue
What could possibly go wrong?

Producer Consumer

counter = counter + 1 counter = counter - 1

register1 = counter register2 = counter

register1 = register1 + 1 register2 = register2 - 1

counter = register1 counter = register2

● counter = counter + 1 statement is implemented in machine level language has 3 steps


1. Load counter value from main memory to local CPU register
2. Increment the value loaded into the register by 1
3. Store the updated value from register to counter variable in main memory 29
A producer consumer problem- Solution 2 issue
What could possibly go wrong?

Producer Consumer

counter = counter + 1 counter = counter - 1

register1 = counter register2 = counter

register1 = register1 + 1 register2 = register2 - 1

counter = register1 counter = register2

● counter = counter - 1 statement is implemented in machine level language has 3 steps


1. Load counter value from main memory to local CPU register
2. Decrement the value loaded into the register by 1
3. Store the updated value from register to counter variable in main memory 30
A producer consumer problem- Solution 2 issue
What could possibly go wrong?

Producer Consumer register1 = counter


counter 5
6
register1 = register1 + 1
counter = counter + 1 counter = counter - 1
counter = register1
register1 5
6
register1 = counter register2 = counter

register1 = register1 + 1 register2 = register2 - 1


register2
counter = register1 counter = register2

Let producer executes first and initial


value of counter is 5
31
A producer consumer problem- Solution 2 issue
What could possibly go wrong?

Producer Consumer register1 = counter


counter 6
5
register1 = register1 + 1
counter = counter + 1 counter = counter - 1
counter = register1
register1 5
6
register2 = counter register2 = counter

register2 = register2 - 1 register2 = register2 - 1


register2 6
5
counter = register2 counter = register2

Consumer executes next and


current value of counter is 6
Final value of counter is 5 32
A producer consumer problem- Solution 2 issue
What could possibly go wrong?

Producer Consumer register2 = counter


counter 6
5
register2 = register2 - 1
counter = counter + 1 counter = counter - 1
counter = register2
register1 5
register1 = counter

register1 = register1 + 1
register2 6
4
counter = register1

If consumer executes first then producer.

Above scenario looks fine when either producer or


consumer executes at a time 33
A producer consumer problem- Solution 2 issue
What could possibly go wrong?

Producer Consumer
counter 5
counter = counter + 1 counter = counter - 1
register1
register1 = counter register2 = counter

register1 = register1 + 1 register2 = register2 - 1


register2
counter = register1 counter = register2

Let’s understand what happens when both producer and


consumer runs concurrently with preemption
34
A producer consumer problem- Solution 2 issue
What could possibly go wrong?

Producer Consumer register1 = counter


counter 4
6
5
register1 = register1 + 1
counter = counter + 1 counter = counter - 1
register2 = counter
register1 5
6
register1 = counter register2 = counter register2 = register2 - 1

register1 = register1 + 1 register2 = register2 - 1 counter = register1


register2 4
5
counter = register1 counter = register2 counter = register2

Now Producer gets preempted and consumer continue execution


Now consumer gets preempted and producer continue execution
Now producer completed and consumer starts
35
Consumer completed
A producer consumer problem- Solution 2 issue
What could possibly go wrong?

Producer Consumer register1 = counter


counter 4
6
5
register1 = register1 + 1
counter = counter + 1 counter = counter - 1
register2 = counter
register1 5
6
register1 = counter register2 = counter register2 = register2 - 1

register1 = register1 + 1 register2 = register2 - 1 counter = register1


register2 4
5
counter = register1 counter = register2 counter = register2

Value of counter supposed to be remain 5 after


producer and consumer executes
36
A producer consumer problem- Solution 2 issue

● We could arrive to 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 i which the access takes place, is
called race a condition.
● To guard against the race condition above, we need to ensure that
only one process at a time can be manipulating the variable counter.

37
Critical Section Problem
● Software Solutions
● Hardware Solution

38
A critical section problem

● Consider a system consisting of n processes {p0, p1, … pn-1}.


● Each process has a segment code, called critical section in which the
process may be changing common variables, updating a table, writing a file
and so on.
● When a process is executing its critical section no other process is to be
allowed to execute in its critical section
● That is no processes are executing in their critical sections at the same time.
● A critical section problem is to design a protocol that the processes can use
to cooperate.

39
A critical section problem

do{ ● Each process must request permission to


Entry section enter its critical section. The section code
implementing this request is the entry
critical section
section.
● At the end of this section, process must
Exit section
release the critical section i.e. exit section
remainder section ● Rest of the section is referred as
remainder section
}while(TRUE)

40
A hardware solution to critical section

● Disable interrupts at entry section - This prevents if


TRIAL ROOM
process is preempted during execution in critical section
other process may start its execution in critical section.
● Enable interrupts at exit section - This ensures that after
a process leaves critical section, it can be preempted in
future.
● Just like a trial room in malls, where
1. a person knocks before entry to ensure nobody is using
it.
2. If it is occupied then he/she waits till it is available
3. Before entering in trial room he/she will lock the door so
that no one can enter inside the trial room
41
A hardware solution to critical section

Implementation issue in hardware solution:-


● In case of uniprocessor system currently execution process cannot be
preempted so it may lead to starvation for other processes.
● In case of multi-processor system processes having critical section may be
executing on different processors. So disable interrupt needs to be
communicated with other processors as well.
● Operating systems using this are not broadly scalable
● Hence this hardware solution is impractical and not acceptable

42
A software solution to critical section

do{ Entry section ● Algorithm is correct as it allows only once


process to be in critical section at a time
while(turn == j); ● What if turn = j and pi wants to enter in critical
section and Pj does not want to enter in critical
critical section section?
● This solution may result into “busy waiting”
turn = j - while Pi is checking for turn == j, Pj is in CS
- Pj gets descheduled but it has not updated
remainder section turn = i
Exit section
- Now Pi waits because turn not equal to i
}while(TRUE); - Again Pj gets scheduled and enters in CS
- This may happen many time and hence Pi
suffers from busy wait.
A general structure of process Pi
43
Solution to critical section

A solution to critical section MUST satisfy three requirements

1. Mutual exclusion:- If process Pi is executing in critical section, no other process


can be executing in their critical section.
2. Progress:- No process running outside the critical section should block the
other interesting process from entering into a critical section when in fact the
critical section is free.
3. Bounded waiting:- A bound must exists on the number of times that other
processes are allowed to enter their critical section after a process has made
a request to enter its critical section and before that request is granted

44
Solution to critical section

Peterson’s solution to critical section


● A good algorithmic software solution
● Two process solution
● Assumption:- load and store instructions are atomic i.e. cannot be interrupted
● Two processes share two variables
1. int turn
2. boolean flag[2]
● The variable turn indicates whose turn is to enter in the critical section
● The flag array is used to indicate if a process is ready to enter in the critical section
● flag[i] == True implies process Pi is ready to enter in 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

Structure of process Pi Structure of process Pj

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

Structure of process Pi flag[i] =True flag[j] =True Structure of process Pj

Let Pi comes first turn = j Now Pj comes


turn = i
Condition false, enter in while(flag[j] && turn == j); while(flag[i] && turn == i); Condition false, enter in
Critical Section Critical section Critical section
Critical Section
Exit critical section
flag[i] = False; flag[j] = False;
47
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
turn== i 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

Structure of process Pi flag[i] =True flag[j] =True Structure of process Pj


Let Pi and Pj come Let Pj execute turn
turn = j turn = i
at same time statement last i.e. Pj
Both processes tries to while(flag[j] && turn == j); while(flag[i] && turn == i); updates turn = i
update turn variable but Critical section Pj waits in while loop and
whichever executes last Pi exit by execution
starts updating flag[i]
in CS =
will update turn value flag[i] = False; False
48
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 = i Critical Section
flag[i] = False; flag[j] = False;
flag[i] = False; flag[j] = False;
True;
remainder section remainder section
}while(True) }while(True)
Pi Pj

Structure of process Pi flag[i] =True flag[j] =True Structure of process Pj

turn = j turn = i As flag[i] becomes False,


while(flag[j] && turn == j); while(flag[i] && turn == i); Pj starts execution
Critical section Critical section Pj terminates by updating
flag[i] = False; flag[j] = False; flag[j] = False
49
Peterson’s Solution to critical section

● Mutual exclusion is preserved as Pi enters in CS only if flag[j] = False


or turn = i.

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

● Busy waiting:- All the software solutions we presented employ a


“busy waiting”
● A process interested in entering in CS is stuck in a loop asking
continuously “can I get in CS” i.e. executing while loop indefinitely.
● Busy waiting is a pure waste of CPU cycle
● Software-based solutions such as Peterson’s solution are not
guaranteed to work on modern computer architectures

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

P1 enters in CS and it communicates with other


processors by sending message as enable interrupts
So that other processes running on different processors waits till P1 53
Releases the CS
Solution to critical section - Hardware solution

do{ ● Many modern systems provide hardware support


Acquire lock for implementing the critical section code
● It provide a special hardware instructions that allow
Critical Section
us either to test and modify the content of a word
Release Lock or to swap the contents of two words Atomically
● All solutions based on the idea of locking
Remainder Section
● Two processes can not have lock simultaneously

}while(TRUE)

54
Solution to critical section - Hardware solution

● Two types of hardware instructions


1. Test and Set - Test memory word and set value atomically
2. Swap - swap the contents of two memory locations atomically

Processor designers have to create such kind of hardware instructions

55
Solution to critical section - Hardware solution

1. Process P wants to enter in critical section


P 01 Lock
2. Check the value of lock (Read from memory)
3. If value is 1 then wait

CS 4. If value is 0 then make it 1 (Write to memory)

5. Enter in critical section


Read operation - Test
6. Make value of Lock 0 (Write to memory)
Write operation - Set
7. Exit critical section
1. Read R1 Lock
2. R1 = 1 Executed Atomically
3. Write Lock R1
56
1. TestAndSet() instruction

boolean TestAndSet(boolean *target)


target TRUE FALSE
{

boolean rv = *target; Updated TRUE TRUE


target
*target = TRUE;
return
return rv; TRUE FALSE
value
}

All the statements gets executed atomically


57
1. TestAndSet() instruction
do{
while(TestAndSet(&Lock));
Shared boolean variable Lock initialized to
FALSE /*Critical Section*/
Lock = FALSE;
Each process willing to enter critical section
executes the given code /*Remainder Section*/
}while(TRUE)

● This solution doesn’t promise bounded waiting as no guarantee that which


process enters into CS
● Solution results in busy waiting as while loop gets executed continuously and it
consumes CPU time. 58
1. TestAndSet() instruction

● TestAndSet() with bounded waiting do{


waiting[i] = TRUE;
key = TRUE;
Key = FALSE while(waiting[i] && key)
P0 P1 P2 P3 P4
Lock = FALSE key = TestAndSet(&Lock);
waiting[i] = FALSE
Waiting[] = FALSE FALSE FALSE FALSE FALSE /*Critical Section*/
j = (i + 1)%n;
while((j != i) && !waiting[j])
j = (j + 1)%n;
● Initially there is no process is in CS if(j == i)
● Lock = FALSE;
Key value is set to FALSE
else
● Lock value is set to FALSE waiting[j] = FALSE;
● Waiting values for all processes is set to FALSE /*Remainder Section*/
}while(TRUE)

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

void Swap(boolean *a, boolean *b) do{


Key = TRUE;
{ while(Key == TRUE)
boolean temp = *a; Swap(&Lock, &Key );
*a = *b; // Critical Section
Lock = FALSE;
*b = temp; // Remainder Section
} }while(TRUE);

The definition of Swap() function Mutual exclusion implementation with


Swap() function
All the instructions from Swap() are Process enters in CS only if Lock value is
executed Atomically FALSE

Bounded waiting and Busy waiting are NOT satisfied


62
Solution to critical section

Mutex Lock

● Previous solutions are complicated and inaccessible to application


programmers
● OS designers build software tools to solve critical section problems
● Simplest tool is “Mutex Lock” which has boolean variable “available”
associated with it to indicate if the lock is available or not
● Two operations available to access Mutex Lock - Acquire() and Release()

Acquire() Release()
{ {
while(!available); /*busy wait*/ available = TRUE;
available = FALSE; }
}

Calls to Acquire() and Release are atomic 63


Solution to critical section

Mutex Lock

● Calls to Acquire() and Release() are Atomic usually implemented via


hardware atomic instructions

do{

Acquire Lock

// Critical Section
This solution results in busy waiting
Release Lock

//Remainder Section

}while(TRUE);

64
Solution to critical section
Semaphore

● Semaphore:- Semaphore was proposed by Dijkstra in 1965


which is a very significant technique to manage
wait(S): concurrent processes by using a simple integer value,
while(S<= 0 ); which is known as a semaphore.
//Busy wait ● Semaphore is a synchronization tool that provides more
S = S - 1; sophisticated ways (than mutex locks) for processes to
synchronize their activities
● Semaphore variables can be accessed by only two atomic
Signal(S): operations wait() or P() and signal() or V()
S = S + 1; ● A process willing to enter into the critical section performs
wait() operation on semaphore variable and after
completing execution in CS it performed signal() operation
on semaphore variable
65
Solution to critical section
Semaphore

● In terms of programming language we can consider semaphore as a data


type
● A data type has two characteristics:
1. Value that it contains
2. Operations can be performed

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

2. Synchronization between two processes


Consider two processes P1 and P2 that require code segment S1 to happen
before code segment 2

P1: Semaphore Synch is initialized to 0


S1;
Signal(Synch); P2 cannot execute S2 until P1 invokes Signal(Synch)
P2:
Wait(Synch); This ensures the synchronization between P1 and P2
S2;
68
Solution to critical section
Semaphore Types: Binary and Counting Semaphore

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.

6. Since it is just a variable, which holds an integer value, it cannot guarantee


bounded waiting. It might happen, that a process may never get a chance to enter
the critical section, which may lead to its starvation. And we don’t want that.

70
Solution to critical section
Semaphore Types: Binary and Counting Semaphore

Binary Semaphore working:


● A semaphore variable initialized to S 01 P1 P2
1 initially
Semaphore S; ● Let P1 wants to enter in CS

wait(S): ● P1 executes wait(S) i.e. S is now 0


Wait(S) Wait(S)
● P1 enters in CS
while(S<= 0 );
//Busy wait ● While P1 executing in CS, P2 arrives
S = S - 1; ● P2 wants to enter in CS, and executes CS CS
wait(S)
● As P1 in CS and S value is 0 P2 is in “busy
wait” state Signal(S) Signal(S)
Signal(S): ● P1 completes execution in CS and calls
S = S + 1; Signal(S) i.e. updates S = 1
● P2 enters in CS and updates value os S to 0
● After completion P2 calls signal(S) and
71
terminates
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

Counting Semaphore Exercise 1

● A counting semaphore S is initialized to 10. Then, 6 wait() or P() operations and


4 signal() or V() operations are performed on S. What is the final value of S?
Ans: Final value of semaphore variable S
= 10 – (6 x 1) + (4 x 1)
= 10 – 6 + 4
=8

74
Solution to critical section
Semaphore Types: Binary and Counting Semaphore

Counting Semaphore Exercise 2

Let's say there are 10 cooperating processes {P1, P2, P3……..P10}.


P1, to P9 executes code 1 and P10 executes code 2. What is the maximum
number of processes can reside in critical section at a time?

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

Counting Semaphore: without busy wait

Wait(Semaphore S) struct Semaphore Signal(Semaphore S)


{ { {
S.value = S.value - 1; S.value = S.value + 1;
int value;
if (S.value < 0) if (S.value <= 0)
{ queue type L; {
put_process(PCB) in L; } select a process from L;

Sleep(); wakeup();
}else }else
return; return;
} }

Because of Sleep() and Wait() busy waiting problem is resolved

76
Solution to critical section
Semaphore Types: Binary and Counting Semaphore

Counting Semaphore: without busy wait

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

● Let P1 wants to enter in CS first ● Let P2 wants to enter in CS now


● P1 performs P(S) and decrement ● P2 performs P(S) and decrement
S.value by 1 S.value by 1
● P1 enters in CS ● P2 enters in CS 77
Solution to critical section
Semaphore Types: Binary and Counting Semaphore

Counting Semaphore: without busy wait

S.value -1
31
2
0 P1 P2 P3 P4 P5 P6

P(S) P(S) P(S) P(S)


S.queue P3
CS CS CS CS CS CS

CS Status P1 P2 P5

● Let P3 wants to enter in CS now


● Let P5 wants to enter in CS now
● P3 performs P(S) and decrement
● P5 performs P(S) and decrement S.value by 1
S.value by 1
● But S.value is < 0 so P3 will be kept in
● P5 enters in CS S.queue and go to sleep() 78
Solution to critical section
Semaphore Types: Binary and Counting Semaphore

Counting Semaphore: without busy wait

S.value -2
-3
-1
31
2
0 P1 P2 P3 P4 P5 P6

P(S) P(S) P(S) P(S) P(S) P(S)


S.queue P3 P4 P6
CS CS CS CS CS CS

CS Status P1 P2 P5

● Let P4 wants to enter in CS now ● Let P6 wants to enter in CS now


● P4 performs P(S) and decrement ● P6 performs P(S) and decrement
S.value by 1 S.value by 1
● But S.value is < 0 so P4 will be kept in ● But S.value is < 0 so P6 will be kept in
S.queue and go to sleep() S.queue and go to sleep() 79
Solution to critical section
Semaphore Types: Binary and Counting Semaphore

Counting Semaphore: without busy wait

S.value -2
-3
-1
31
2
0 P1 P2 P3 P4 P5 P6

P(S) P(S) P(S) P(S) P(S) P(S)


S.queue P3 P4 P6
CS CS CS CS CS CS

CS Status P1 P2 P5

● At this time P1, P2 and P3 currently executing the critical section


● P3, P4 and P6 are in sleep() mode and kept in S.queue
● As S.value is initialized to 3, maximum 3 processes can access CS at a time
● If one process exit from CS then a process from S.queue will enter in CS
80
Solution to critical section
Semaphore Types: Binary and Counting Semaphore

Counting Semaphore: without busy wait

S.value -3
-2 P1 P2 P3 P4 P5 P6

P(S) P(S) P(S) P(S) P(S) P(S)


S.queue P3 P4 P6
CS CS CS CS CS CS

CS Status P1 P2 P5 P6 V(S)

● But S.value is <= 0 that means there is at


● Let P1 wants to exit from CS now
least one process in S.queue

● P1 performs V(S) and increment S.value ● Before exiting CS P1 wakeups a process


by 1 lets say P6 from S.queue and leaves CS
81
Solution to critical section
Semaphore Types: Binary and Counting Semaphore

Counting Semaphore: without busy wait

S.value -2
-1 P1 P2 P3 P4 P5 P6

P(S) P(S) P(S) P(S) P(S) P(S)


S.queue P3 P4
CS CS CS CS CS CS
V(S)
CS Status P4 P2 P5 P6 V(S)

● But S.value is <= 0 that means there is at


● Let P5 wants to exit from CS now
least one process in S.queue

● 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

Counting Semaphore: without busy wait

S.value -1
0 P1 P2 P3 P4 P5 P6

P(S) P(S) P(S) P(S) P(S) P(S)


S.queue P3
CS CS CS CS CS CS
V(S)
CS Status P4 P2 P3 P6 V(S) V(S)

● But S.value is <= 0 that means there is at


● Let P2 wants to exit from CS now
least one process in S.queue

● 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

Counting Semaphore: without busy wait

S.value 01 P1 P2 P3 P4 P5 P6

P(S) P(S) P(S) P(S) P(S) P(S)


S.queue
CS CS CS CS CS CS
V(S) V(S)
CS Status P4 P3 P6 V(S) V(S)

● S.value is > 0 that means there is no


● Now let P4 wants to exit from CS
process in S.queue

● P4 performs V(S) and increment S.value ● P4 leaves CS


by 1
84
Solution to critical section
Semaphore Types: Binary and Counting Semaphore

Counting Semaphore: without busy wait

S.value 21 P1 P2 P3 P4 P5 P6

P(S) P(S) P(S) P(S) P(S) P(S)


S.queue
CS CS CS CS CS CS

CS Status P3 P6 V(S) V(S) V(S) V(S) V(S)

● S.value is > 0 that means there is no


● Now let P3 wants to exit from CS
process in S.queue

● P3 performs V(S) and increment S.value ● P3 leaves CS


by 1
85
Solution to critical section
Semaphore Types: Binary and Counting Semaphore

Counting Semaphore: without busy wait

S.value 2
3 P1 P2 P3 P4 P5 P6

P(S) P(S) P(S) P(S) P(S) P(S)


S.queue
CS CS CS CS CS CS

CS Status P6 V(S) V(S) V(S) V(S) V(S) V(S)

● S.value is > 0 that means there is no


● Now let P6 wants to exit from CS
process in S.queue

● P6 performs V(S) and increment S.value ● P6 leaves CS


by 1
86
Problems associated with Semaphore
Deadlock

● The implementation of semaphore with a waiting queue may result in a


situation where two or more processes are waiting indefinitely for an event
that can be caused only by one of the waiting processes
Let two binary semaphore variables S and Q initialized to 1

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

● A process may not be removed from its Semaphore queue in which it is


suspended
IN
S.List

P1 P7 P4 P6

OUT

If suspended ( sleep() ) processes put into a List which follows LIFO


order then old processes may not resumed by wait() call. This may lead
to indefinite blocking or starvation
88
Problems associated with Semaphore
Priority Inversion CASE 1

Low
L L is running on CPU but not in CS
Priority

Critical Section H arrives in ready queue and needs to


Medium execute
M
Priority
L
H
As H has higher priority than L,
H preempts L and start running
High CPU
H
Priority H completes execution then L resumes

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

Critical Section H arrives in ready queue and needs to


Medium execute but not in CS
M
Priority
H
L
As H has higher priority than L,
H preempts L and start running
High CPU
H
Priority H completes execution then L resumes

H
L

Ready Queue
90
Problems associated with Semaphore
Priority Inversion CASE 3

L is running on CPU and in CS


Low
L L
Priority H arrives in ready queue and needs to
execute in CS
Critical Section
Medium As H has higher priority than L, but as L is
M
Priority already in CS and H also demands to enter in
L
H
same CS, H waits till L exit from CS
High CPU
H L exit from CS.
Priority
H will not wait till L release the CPU. As soon
H
L as L exit from CS it gets preempted.
H completes its execution then L resumes
Ready Queue
91
Problems associated with Semaphore
Priority Inversion CASE 4

L is running on CPU and in CS


Low H arrives in ready queue and needs to
L L
Priority execute in CS
Critical Section As H has higher priority than L, but as L is
Medium already in CS and H also demands to enter in
M
Priority
M1
L same CS, H waits till L exit from CS

High CPU A process M1 arrives, but do not want CS


H
Priority

As M1 has higher priority than L, L gets


M1
L H preempted and M1 starts execution

Ready Queue
92
Problems associated with Semaphore
Priority Inversion CASE 4

Low Now M1 terminates and M2 arrives in but do


L L not want CS of L
Priority
Again M2 has higher priority than L, so M2
Critical Section
starts execution
Medium
M
Priority Note that L is still holding CS and H is waiting
M2
M1
for L to release CS
High CPU Though H is having higher priority than M1,
H
Priority M2 and also they don’t have common CS, H is
in waiting state - Priority Inversion
M2 L H
If processes like M1, M2 keep coming H will
Ready Queue suffer from starvation
93
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 6 S 1 Full 0 Signal(Empty)

Given: A binary semaphore S initialized to 1


A bounded Buffer of size ‘N=6’ to store produced items
A counting semaphore Empty initialized to ‘N=6’ and Full is initialized to 0
in and out pointers to point current empty slot and filled slot respectively
94
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 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)

Let producer wants to produce an item P Producer release CS by calling Signal(S)


Producer first check if there is an empty slot
in the buffer or not by Wait(Empty) operation Producer increases value of full by 1 by calling
Signal(Full)
Producer Enters into CS by Wait(S)
Buffer[in] = P
95
in = (in + 1) mod N = (0 + 1) mod 6 = 1
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 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 4
5 S 01 Full 21 Signal(Empty)

Let producer wants to produce an item P Producer release CS by calling Signal(S)


Producer first check if there is an empty slot
in the buffer or not by Wait(Empty) operation Producer increases value of full by 1 by calling
Signal(Full)
Producer Enters into CS by Wait(S)
Buffer[in] = P
96
in = (in + 1) mod N = (1 + 1) mod 6 = 2
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 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 3
4 S 0
1 Full 21
3 Signal(Empty)

Similarly producer produces item till buffer is Full

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)

Similarly producer produces item till buffer is Full

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)

Similarly producer produces item till buffer is Full

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)

Similarly producer produces item till buffer is Full

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)

Now producer cannot enter into CS as Wait(Empty) updates value of Empty to -1


That means buffer is full!
Producer will wait till consumer consumes an item from the buffer
This ensures that, producer can enter in CS only if there is a free slot in buffer

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);

Q. This solution will lead to undesirable problem called as


A) Starvation B) Deadlock
C) Race condition D) Convoy Effect
105
Practice Question 2
Consider following threads T1, T2 and T3 executing on single processor, synchronized using 3
binary semaphores S1, S2 and S3. Threads can be context switched in any order at any time.
Which initialization of semaphores would print the sequence BCABCABCABCA…..?

● Initialize S1 = 1, S2 = 0 and S3 = 0. This will


T1 T2 T3 allow only T2 to execute in CS.
while(TRUE) while(TRUE) while(TRUE) ● T2 in CS prints “B”
{ { { ● Then T2 Singal(S3) this will allow T1 to
Wait(S3); Wait(S1); Wait(S2); enter in CS to print “C”
print(“C”); print(“B”); print(“A”); ● Then T1 leaves the CS by calling Signal(S2)
Signal(S2); Signal(S3); Signal(S1); this will allow T3 to enter in CS by
} } } executing Wait(S2).
● T3 prints “A” in CS and leaves by Signal(S1).
● Again T2 can enter in CS and prints “A”
A) S1 = 1; S2 = 1; S3 = 1; C) S1 = 0; S2 = 0; S3 = 0;
and so on
B) S1 = 1; S2 = 0; S3 = 0; D) S1 = 0; S2 = 1; S3 = 0;
106
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. }

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

● Let a file is shared between two processes


● The processes can perform read/write
operations on shared file
● If two processes read concurrently then no
adverse effect will result
● However, if a process is writing and another
process performs read/write simultaneously
Reader then chaos may ensue Writer
● Ex. Checking Live status of Train is read
operation while Booking a ticket is a write
operation
109
Reader Writer Problem

● Let’s say we have a database that is shared among multiple


processes
● All processes are cooperative (executing concurrently) and
performing read or write operations
● Processes which are performing read operations are referred as
readers and processes which are performing write operations are
referred as writers

110
Reader Writer Problem

Database Database Database Database

R R R W W R W W

No Problem Problem Problem Problem

111
Reader Writer Problem
Reader Writer
readcnt 0 Shared Data
do { do {
wait(mutex);
readcnt++; wait(wrt);

// performs the write


if (readcnt==1)
wait(wrt); Mutex on readcnt signal(wrt);
signal(mutex);
wait(mutex); } while(true);
readcnt--;
if (readcnt == 0)
signal(wrt); wrt
signal(mutex);
} while(true);

● mutex variable ensure mutual exclusion while updating readcnt


● wrt variable ensures only one writing process can access CS
112
Dining Philosopher problem

● This is another classical problem of


synchronization
● There are 5 philosophers sitting on a dining
table
● Every philosopher has a bowl of rice
● There are 5 forks available on the table
● To eat, philosopher must own two forks, one
from left neighbour and other from right
neighbour
● Philosophers can only perform thinking or
eating
● Task:- Allocate resources (forks) to
philosophers such a way that it will not
result in deadlock or starvation
113
Dining Philosopher problem

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)

Is this solution deadlock free?

What if all the philosophers get hungry at the


same time and grabs only one fork? 115
Dining Philosopher problem

Other solutions

1. Allow at most four philosophers to be


sitting simultaneously at the table
2. Allow philosophers to pick up the
chopsticks only if both chopsticks are
available
3. Use asymmetric solution:- An odd
philosopher picks up first her left fork
and then her right fork, whereas an
even philosopher picks up her right fork
then her left fork

116
Problems associated with Semaphore
Summary

● Incorrect use of Semaphore may result in

Deadlock

Starvation

Priority Inversion
● Solution:- use some high level programming language constructs such as
monitors

117
Solution to critical section problem - Monitors
Monitors

● In case of semaphores, its programmer’s responsibility to ensure the proper


sequence of wait() and Signal()
● We have seen, incorrect ordering of wait() and signal() potentially results into
serious problems like deadlock and starvation
● Such errors are even difficult to detect, since these errors happen only if
specific execution sequence takes place

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

monitor monitor_name ● To deal with such errors, researchers have


{
// shared variable declaration developed high level language constructs -
procedure P1(. . . ){ Monitor
... ●
}
A monitor is a high level abstraction that
procedure P2(. . . ){ provides convenient and effective mechanism
... for process synchronization.
}
procedure Pn(. . . ){ ● Abstract Data Type - Internal variables are
... accessed only by code within the procedure.
}
initialization code( . . . ){ ● Only one process active within the monitor at a
... time
}
}
● Here mutual exclusion is guaranteed by OS
119
Solution to critical section problem - Monitors
Monitors - Schematic view

Shared data

Entry Queue

● Monitor is an abstract data type (ADT) which contains


1. Shared variables
2. Procedures
3. Condition variables

● Cooperative processes wants to access shared variables within


monitor
Operations ● A process outside monitor cannot update the shared variables
within monitors directly
● Procedures/operations can be called from outside the monitor
Initialization
code
120
Solution to critical section problem - Monitors
Solution to producer consumer problem using Monitor
monitor ProducerConsumer
condition full, empty;
Producer()
int count;
{
while (TRUE)
procedure enter();
{
{
make_item(widget);
if (count == N) wait(full); // if buffer is full, block
put_item(widget); // put item in buffer
ProducerConsumer.enter;
count = count + 1; // increment count of full slots
}
if (count == 1) signal(empty); // if buffer was empty, wake consumer
}
}
procedure remove(); Consumer()
{ {
if (count == 0) wait(empty); // if buffer is empty, block while (TRUE)
remove_item(widget); // remove item from buffer {
count = count - 1; // decrement count of full slots ProducerConsumer.remove;
if (count == N-1) signal(full); // if buffer was full, wake producer consume_item;
} }
count = 0; }
end monitor;
121
DeadLocks

122
DeadLocks

● System model
● Deadlock characterization
● Methods for handling deadlocks
● Deadlock prevention
● Deadlock Avoidance
● Deadlock Detection
● Recovery from deadlock

123
DeadLocks

● Deadlock is just like a disease to computer system


● If there is a disease like covid we follow
1. Disease Prevention - by vaccination
2. Disease Avoidance - by social distancing
3. Disease Detection - by Swab/RTPCR
4. Recovery from Disease - by taking medicine and following
doctor's advice.

124
DeadLock example - Traffic Gridlock

Deadlock

125
System Model
Types of resources

1 2

IO devices Printers Files Memory


addresses

1 2
Computing P1 P1 P2 P4 Pn
3 4 resources
126
System Model
Types of resources

● A system consists of ‘m’ number of resources and each resource Ri has Wi


instances
● There are ‘n’ number of processes running in the system at any time
● Each process utilizes resources as follows

1. Request:- The process request the resource. If the request cannot be


granted immediately, then the requesting process must wait until it can acquire
the resource.

2. Use:- The process operate on the resource.

3. Release:- The process releases the resource after use.

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

Necessary conditions for deadlock

Deadlock can occur if following four conditions hold simultaneously

1. Mutual exclusion:- only one process at a time can use a resource


2. Hold and wait:- a process holding at least one resource is waiting to acquire additional
resources held by other processes.
3. No preemption:- a resource can be released only voluntarily by the process holding it,
after that process has completed its task.
4. Circular wait:- there exists a set {P0, P1, ……. Pn } of waiting processes such that P0 is
waiting for resource that is held by P1, P1 is waiting for resource that is held by P2, …….. Pn-
1 is waiting for resource that is held by Pn and Pn is waiting for resource that is held by P0

All four conditions must hold for a deadlock to occur

129
Deadlock characterization

Resource Allocation Graph

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 Allocation Graph Example


The sets P, R, and E:
● P = {P1, P2, P3}
R1 R3 ● R = {R1, R2, R3, R4}
● E = {P1->R1, P2 -> R3, R1->P2, R2->P2, R2->P1, R3->P3}

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

Resource Allocation Graph to detect deadlock

● 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

RAG with deadlock RAG with cycle but no deadlock 132


Methods to handle deadlocks

We can deal with the deadlock problem in one of the three ways

1. Deadlock prevention:- we can use a protocol to prevent or avoid


deadlocks, ensuring that the system will never enter a deadlock state.
2. Detection and Recovery:- we can allow the system to enter a
deadlocked state, detect it, and recover.
3. Deadlock Avoidance:- Requires that OS be given advance information
resource requirement. Based on resource by each process, which
resource assignment can lead to deadlock can be determined.
4. Deadlock Ignorance:- We can ignore the problem altogether and
pretend that deadlocks never occur in the system Ostrich bird during sand storm

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

Hold and wait

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

● First necessary condition for deadlocks is Mutual Exclusion


● Mutual exclusion:- The mutual exclusion must hold for non sharable resources.
For example a printer (non sharable) cannot be shared by several
processes but a file with read-only access (shareable) can be shared
among many processes.
We cannot prevent deadlocks by denying the mutual exclusion condition
because some resources are intrinsically non shareable

135
Methods to handle deadlocks
Deadlock Prevention - hold and wait

● Second necessary condition for deadlock is 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.

Protocol 1: Allocate all resources before a process starts its execution.


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.

136
Methods to handle deadlocks
Deadlock Prevention - hold and wait

Protocol 1: Allocate all resources before a process starts its execution


Let a process P wants to perform following tasks
DVD HDD
P
COPY

Copy data from DvD to a file on HDD

Perform sort in file

Print the file

Printer 137
Methods to handle deadlocks
Deadlock Prevention - hold and wait

Protocol 1: Allocate all resources before a process starts its execution


Let a process P wants to perform following tasks
DVD HDD
P
COPY

There are 3 resources requested by P


1. DvD
2. File on a hard disk
3. Printer

As per protocol 1 process P first request all resources.


P1 will start its execution only if all resources are allocated.

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

There are 3 resources requested by P


1. DvD
2. File on a hard disk
3. Printer

As per protocol 2 process P first request DvD and file


resources. After copying file and sorting it will release DvD
and File. Again it will demand file and printer to continue its
execution Printer 139
Methods to handle deadlocks
Deadlock Prevention - hold and wait

Protocol 1: Allocate all resources before a process starts its execution.


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.
Both of these protocols have two main disadvantages:-
1. Poor resource utilization, since resources may be allocated but unutilized for
longer periods of time.
2. Starvation is possible as 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.

140
Methods to handle deadlocks
Deadlock Prevention - No preemption

● Third necessary condition for deadlock is that there be no preemption of


resources that have already been allocated.
● We must ensure that this condition do not hold to prevent deadlock
● If a process is holding some resources and requests another resource that
cannot be immediately allocated to it, then all resources that process
currently holding are preempted.
● 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 new ones that it is requesting.

141
Methods to handle deadlocks
Deadlock Prevention - Circular wait

● Fourth necessary condition for deadlock is the 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.
● A unique number is allocated to each resource using one-to-one function F:R-
>N
● A process can request any number of instances of resource type Ri. After
that the process can request resource type Rj if the F(Rj)>F(Ri).
● A process requesting an instance of type Rj must have released any
resources Ri such that F(Ri) >= F(Rj)

142
Methods to handle deadlocks
Deadlock Avoidance

● Deadlock prevention techniques prevent deadlock by restraining how


requests can be made.
● The restraints ensure that at least one necessary condition for deadlock
cannot occur an hence deadlocks cannot hold.
● Possible side effects of this method is low device utilization and reduced
system throughput
● An alternative method for avoiding deadlocks is to require additional
information about how resources are to be requested.
● The system keeps track on
1. Resources currently available
2. Resources currently allocated to each process
3. Future resource requests by each process
4. Future release of resources by each process
143
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

● Applicable to single instance of a resource type


● Each process must a priori claim maximum resource use
● Use a variant of resource allocation with claim edges
● Claim edge Pi -> Rj indicated that a process Pi may request resource Rj
represented by a dashed line
● Claim edge converted into request edge when process requests a resource
● Request edge is converted into assignment edge when the resource is
allocated to the process
● When resource is released by a process, assignment edge reconverts to
claim edge.
● Resources must be claimed a priori in the system
● A cycle in the graph implies that the system is in unsafe state

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

● P1 is holding resource R1 and claim on R2


P1 P2
● P2 is requesting R1 and has claim on R2
● No cycle so system is in safe state

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

Resource allocation graph algorithm


● Suppose that a process Pi requests a resource Rj
● The request can be granted only if converting the
R1
request edge to assignment edge does not result in
the formation of the cycle in the resource allocation
graph.
P1 P2 ● Otherwise, process must wait

R2

150
Methods to handle deadlocks
Deadlock Avoidance - Banker’s Algorithm

● Multiple instances of resource types


● Each process must a priori claim the maximum use
● When a process request a resource it may have to wait
● When process gets all of its resources it must return them in a finite amount
of time

151
Methods to handle deadlocks
Deadlock Avoidance - Banker’s Algorithm

Data structures used in Banker’s algorithm


Let n be the number of processes and m be the number of resources
available - a vector/array of length m.
If available[j] = k, then there are k number of resources of type Rj
max - n x m matrix
If max[i,j] = k, then process Pi requests k number of resources of type Rj
allocation - n x m matrix
If allocation[i,j] = k, then there are k number of resources of type Rj allocated to process Pi
need - n x m matrix
If need[i,j] = k, then Pi need at most k more instances of Rj to complete its task
need[i,j] = max[i,j] - allocation[i,j]

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.

Initialize work = available and finish[i] = False for i = 0, 1, …..,n-1

2. Find an index i such that both


a. finish[i] == False
b. Needi <= work

If no such i exists, go to step 4


3. work = work + allocation
finish[i] = True
Go to step 2
4. If finish[i] == True for all i, then system is in safe state, otherwise in unsafe state

153
Methods to handle deadlocks
Deadlock Avoidance - Banker’s Algorithm

Resource request algorithm


Let requesti be the request vector for process Pi. If requesti[j] == k, then process Pi wants k
instances of resource type Rj. When a request for resources is made by a process Pi, the following
actions are taken:
1. If requesti <= needi, go to step 2. Otherwise, raise an error condition, since the process has
exceeded maximum claim.
2. If requesti <= available go to step 3. Otherwise, Pi must wait, since the resources are not
available.
3. Have the system pretend to have allocated the requested resources to process Pi by
modifying the state as follows:
available = available - requesti
allocationi = allocationi + requesti
needi = needi - requesti
154
Methods to handle deadlocks
Deadlock Avoidance - Banker’s Algorithm Example

● 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:

Allocation Max Available


Process
A B C A B C A B C

Given allocation and Max need check


P0 0 1 0 7 5 3 3 3 2
whether system will lead to deadlock or
P1 2 0 0 3 2 2 not. If not find out the safe sequence.
P2 3 0 2 9 0 2

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

Allocation Max Available Need Total resources A - 10 B - 5 C - 7


Process
A B C A B C A B C A B C

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

Available = Total Resources - Total Allocation

Need = Max - Allocation


156
Methods to handle deadlocks
Deadlock Avoidance - Banker’s Algorithm Example

Allocation Max Available Need Total resources A - 10 B - 5 C - 7


Process
A B C A B C A B C A B C

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

P0 needs 7 instance of resource A, 4 of B and 3 of C.


Available instances of resources cannot satisfy this requirement
157
Methods to handle deadlocks
Deadlock Avoidance - Banker’s Algorithm Example

Allocation Max Available Need Total resources A - 10 B - 5 C - 7


Process
A B C A B C A B C A B C

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

P1 needs 1 instance of resource A, 4 of B and 3 of C.


Available instances of resources can satisfy this requirement, so add in safe sequence.
After P1 completes, update available = available + resources of P1 = 3 3 2 + 2 0 0 = 5 3 2 158
Methods to handle deadlocks
Deadlock Avoidance - Banker’s Algorithm Example

Allocation Max Available Need Total resources A - 10 B - 5 C - 7


Process
A B C A B C A B C A B C

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

P2 needs 6 instance of resource A, 0 of B and 0 of C.


Available instances of resources cannot satisfy this requirement. Go to next process
159
Methods to handle deadlocks
Deadlock Avoidance - Banker’s Algorithm Example

Allocation Max Available Need Total resources A - 10 B - 5 C - 7


Process
A B C A B C A B C A B C

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

P3 needs 0 instance of resource A, 1 of B and 1 of C.


Available instances of resources can satisfy this requirement so add P3 in sequence.
After P3 completes, update available = available + resources of P3 = 5 3 2 + 2 1 1 = 7 4 3 160
Methods to handle deadlocks
Deadlock Avoidance - Banker’s Algorithm Example

Allocation Max Available Need Total resources A - 10 B - 5 C - 7


Process
A B C A B C A B C A B C

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

P4 needs 4 instance of resource A, 3 of B and 1 of C.


Available instances of resources can satisfy this requirement so add P4 in sequence.
After P4 completes, update available = available + resources of P3 = 7 4 3 + 0 0 2 = 7 4 5 161
Methods to handle deadlocks
Deadlock Avoidance - Banker’s Algorithm Example

Allocation Max Available Need Total resources A - 10 B - 5 C - 7


Process
A B C A B C A B C A B C

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

Again Check with remaining processes. P0 needs 7 instance of resource A, 4 of B and 3 of C.


Available instances of resources can satisfy this requirement so add P0 in sequence.
After P0 completes, update available = available + resources of P3 = 7 4 5 + 0 1 0 = 7 5 5 162
Methods to handle deadlocks
Deadlock Avoidance - Banker’s Algorithm Example

Allocation Max Available Need Total resources A - 10 B - 5 C - 7


Process
A B C A B C A B C A B C

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

Finally, P2 needs 6 instance of resource A, 0 of B and 0 of C.


Available instances of resources can satisfy this requirement so add P2 in sequence.
After P2 completes, update available = available + resources of P3 = 7 5 5 + 3 0 2 = 10 5 7 163
Methods to handle deadlocks
Deadlock Avoidance - Banker’s Algorithm Example

Allocation Max Available Need Total resources A - 10 B - 5 C - 7


Process
A B C A B C A B C A B C

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

You might also like