Title: Process Synchronization
1Process Synchronization
- Race Conditions
- Example Spooler directory with slots index
variable two processes attempt concurrent access
Process A
5
6
7
4
. . .
. . .
prog1
prog2
prog3
In7
Process B
Out 4
2Race Conditions...
- Process A reads in and is switched..
- Process B reads in, changes its contents to his
job and moves in by one - Process A gets the control and changes the
contents of his in to his job and moves the
value of in by one - Result in has a correct value but the
printing job of B is lost. - Comment common data structures to A, B
3Critical Sections
- Mutual Exclusion
- Critical section
- Conditions needed
- No two processes in critical sections
simultaneously - Process outside its critical section may not
block another process - There is a limit on the number of times a
process can enter the CS while another waits
(i.e. no starving) - No assumptions about speeds, no. of cpus, etc.
- 1st condition avoids race condition, but is not
sufficient for correct concurrent cooperation
4Mutual Exclusion - attempts...
- 1. Disable interrupts
- Violates condition 3
- Too much responsibility for a user process
- 2. Lock variables
- If Lock 0 then set it to 1 and enter CS
- else wait...
- Race conditions occur when context is changed
between read 0 and write 1
5.. another attempt..
- 3. Strict alternation -
- while (TRUE)
- while (turn ! 0) / wait /
- critical_section()
- turn 1
- non_critical_section()
-
- Violation process blocked by another process
outside its critical section !!
- while (TRUE)
- while (turn ! 1) / wait /
- critical_section()
- turn 0
- non_critical_section()
-
6Petersons Solution
- define FALSE 0
- define TRUE 1
- define N 2
- int turn / whose turn is it ? /
- int interestedN / all initially 0
(FALSE) / - void enter_region(int process) / who is
entering 0 or 1 ? / -
- int other / number of other process /
- other 1- process / opposite of process
/ - interested(process) TRUE / signal that
youre interested / - turn process / set flag /
- while (turn process
- interested(other) TRUE) / null statement
/ -
- void leave_region(int process) / who is
leaving 0 or 1 ? / -
- interested(process) FALSE / departure from
critical region /
7Petersons Solution - observations
- Solution for two processes only
- For N processes some numbering of the queue is
needed.. - Uses busy-wait
- Memory writes are assumed to be atomic
interested lt-- TRUE - a basic assumption for all solutions is
- No Process dies inside a critical section
8 and for N Processes ...
- int valueN / processes get waiting
numbers / - int busyN / just a flag... /
- void enter_region(int i ) / process i
entering.. / -
- busy(i) TRUE / guard the value selection
/ - value(i) max(value(0), value(1), ,
value(N-1)) 1 / LAST in line / - busy(i) FALSE
- for(k0 k lt N k )
- while (busy(k) TRUE) / wait before
checking / - while((value(k) ! 0) ((value(k), k) lt
(value(i), i))) / wait / -
-
- void leave_region(int i )
-
- value(i ) 0
9Using the Hardware - TSL instruction
- TSL - Test and Set Lock
- read a memory word into a register AND store a
nonzero value into that word, in an indivisible
instruction sequence - enter_region
- tsl R1,flag copy flag to R1 and set flag
to 1 - cmp R1,0 was flag 0 ?
- jnz enter_region if not zero, Lock was set, so
loop - ret return enter critical region
- leave_region
- mov flag,0 set flag to 0
- ret return critical region left
10Implement fairness with TSL
- test_and_set(int flag) - TSL 1,flag and
return(flag) -
- interested(i) TRUE
- test TRUE
- while(interested(i) TRUE test TRUE)
- test test_and_set(lock)
- interested(i) FALSE
-
- . . . critical section . . .
-
- j i1 n
- while(j ! i !(interested(j))) j n
- if(j i) lock FALSE
- else interested(j) FALSE
11Synchronization Constructs - Semaphores
- Two operations define a semaphore S
- DOWN(S)
- while(s lt 0)
- s s - 1
- UP(S)
- s s 1
- Operations on the counter are performed
indivisibly - S is non-negative
12Synchronizing with Semaphores
- Mutual Exclusion
- down(mutex)
- critical section
- up(mutex)
- Synchronization
- requirement S2 executed after S1 is completed
- Synch 0
- P1 S1 P2 DOWN(Synch)
- UP(Synch) S2
13 1st assignment - suspend()
- A thread wants to read messages -
- loop
- enter() critical section and check mailbox
- if mailbox empty - leave(), suspend()
- otherwise, read mail item and leave()
- end loop
- The Mailer wants to add message -
- enter() critical section
- add message (if needed wakeup suspended
thread) - leave()
- enter() and leave() will block the thread, if
needed
14 deadlocks with Semaphores...
- Two processes p0 and p1
- Two semaphores Q and S
- p0 p1
- down(S) down(Q)
- down(Q) down(S)
- . ..
- up(S) up(Q)
- up(Q) up(S)
- p0 does the first line, then p1 and so on...
15Whats wrong with busy waiting
- Wastes cpu time by waiting
- Side effects
- Two processes with different priorities arrive at
their critical section in an order inverse to
their priorities - The higher priority process gets time-slices
- The lower priority process cannot complete its
processing of its critical section and leave ! - Priority Inversion
161st attempt - sleep and wakeup
- sleep() is a system call that blocks the calling
process indefinitely - wakeup(p) unblocks process p
- A process calls sleep() when it tries to enter
and finds that the lock is up - Each process calls wakeup(other) when leaving the
critical section...
17Problems with sleep() and wakeup()
- Process 0 checks lock TRUE and is blocked
before putting itself to sleep - Process 1 generates a wakeup(process 0), after
leaving its critical section - The system call wakeup(process 0) is wasted
because process 0 is not yet sleeping - Process 0 is unblocked later and calls sleep()
- Process 1 has to go through its CS again, to
wakeup process 0
18Concrete problem - bounded buffer
- Two processes (at least) use a shared buffer in
memory - The buffer is finite (i.e. bounded)
- One process writes on the buffer and the other
process reads from it - A full buffer stops the writer (producer)
- An empty buffer stops the reader (consumer)
19Bounded Buffer with sleep(), wakeup()
- A producer process calls sleep() when the mutual
buffer is full - A consumer process calls sleep() when the mutual
buffer is empty - Each process calls wakeup(other) when some
condition on the mutual buffer is true
20Producer-consumer with sleep and wakeup
- define N 100 / size of buffer /
- int count 0 / number of items in buffer
/ - void producer(void)
-
- int item
- while(TRUE) / forever... /
- produce_item(item) / produce an item /
- if (count N) sleep() / go to sleep if
buffer is full / - enter_item(item) / insert item into buffer
/ - count count 1 / increment count of items
/ - if (count 1) wakeup(consumer) / was
buffer empty ? / -
21Producer-consumer with sleep and wakeup
- void consumer(void)
-
- int item
- while(TRUE) / forever... /
- if (count 0) sleep() / go to sleep if
buffer is empty / - remove_item(item) / remove item from
buffer / - count count - 1 / increment count of
items / - if (count N - 1) wakeup(producer) / was
buffer full ? / - consume_item(item) / print item /
-
22Race conditions with sleep() and wakeup()
- Consumer checks buffer0 and is blocked before
putting itself to sleep - Producer generates a wakeup(consumer), based on
an empty buffer - The system call wakeup(consumer) is wasted
because consumer is not yet sleeping - Consumer is unblocked later and calls sleep()
- Producer continues running and fills up the
buffer, then calls sleep(). - Both processes sleep forever
23Semaphores with blocking (Dijkstra 1965)
- An integer counter S
- Operation DOWN
- if S gt 0 decrement S,
- else sleep
- Operation UP
- If (S 0 there are sleeping processes) wake
one up (S remains 0) , - else increment S
- this semaphore has only nonnegative values
- comment UP and DOWN are atomic operations
24Negative-valued Semaphores
- An integer counter S
- Operation DOWN
- decrement S and check value, if S lt 0, sleep
- Operation UP
- increment S , if processes are sleeping (S lt 0)
, wake one up - a semaphore may have negative values
- the magnitude of the negative value is the
number of waiting processes - negative values arise because of the switching
of lines of decrement and check (from the
classical semaphore)
25Implementation of Semaphores
- struct semaphore
- int value, flag // flag is a variable for
testset - true when 0 - list_proc L
-
- DOWN(S) repeat until testset(S.flag)
- S.value S.value - 1
- if(S.value lt 0)
- add process to S.L
- set-up p as blocked
- S.flag 0
- --gt scheduler
- else S.flag 0
- UP(S) repeat until testset(S.flag)
- S.value S.value 1
- if(S.value lt 0)
- remove a process P from S.L
- wakeup(P)
- S.flag 0
26Atomicity of Semaphores
- The use of TSL can work for several cpus,
enabling access of only one cpu at a time to the
semaphore itself - For a single cpu one can simply use disable
interrupts - The use of disable interrupts is limited to
several lines of (system) code - acceptable for the system to do so
- locks with the TSL instruction - busy-waiting
27Semaphores for the Producer-Consumer problem
- define N 100 / Buffer size /
- typedef int semaphore
- semaphore mutex 1 / access control to
critical section / - semaphore empty N / counts empty buffer slots
/ - semaphore full 0 / full slots /
- void producer(void)
- int item
- while(TRUE)
- produce_item(item) / generate something...
/ - down(empty) / decrement count of empty /
- down(mutex) / enter critical section /
- enter_item(item) / insert into buffer /
- up(mutex) / leave critical section /
- up(full) / increment count of full slots /
-
28Semaphores for the Producer-Consumer problem
- void consumer(void) int item while(TRUE)
down(full) / decrement count of full
/ down(mutex) / enter critical section
/ remove_item(item) / take item from buffer)
/ up(mutex) / leave critical section
/ up(empty) / update count of empty
/ consume_item(item) / do something...
/ Comment up() and down() are simple
atomic operations
29Semaphores for the mailboxes ...
- In the 1st assignment a thread blocks on an empty
mailbox and mailboxes have to be protected for
read/write - two semaphores rw for read/write et for
empty - thread mailer
- down(et) down(rw)
- down(rw) add_message
- read_message up(et)
- up(rw) up(rw)
- .. ...
30Bounded-buffer for sent messages
- Threads use the system call send() to send
messages, which are then stored in a large buffer
for the mailer to deliver to threads mailboxes - The buffer is bounded and so send() is a
producer and the inner function of the Mailer
that extracts the messages and delivers them to
their destination is a consumer - These two functions must use two common
semaphores to implement a synchronized
bounded-buffer and initialize one of the
semaphores to the (user defined) size of the
buffer N
31Counting and Binary semaphores
- binary-semaphore S1, S2
- down(S) up(S)
- down(S1) down(S1)
- S.value-- S.value
- if(S.value lt 0) if(S.value lt 0) up(S2)
- up(S1) up(S1)
- down(S2)
- else up(S1)
-
- This is the negative implementation of a
general semaphore
32More on Synchronization...
- Three processes p1 p2 p3
- semaphores s1, s2
- p1 p2 p3
- down(s1) down(s2) down(s2)
- .. code .. .. code .. .. code ..
- up(s2) up(s2) up(s1)
- the ordering of the processes is p1(p2p3)
- --gt ordering can be done by events (on a clock)
33Event Counters
- Integer counters with three operations
- Advance(E) increment (atomically) E by 1 wake
up relevant sleepers - Await(E,v) wait until E gt v. sleep if E lt v.
- Read(E) returns the current value of E
- Only increase, never decrease
- For the EC implementation of a bounded-buffer
problem no Read() is needed. Only for absolute
synchronization
34producer-consumer with Event Counters
- define N 100typedef int event_counter event
_counter in 0 / counts inserted items
/event_counter out 0 / items removed from
buffer /void producer(void)int item,
sequence 0 - while(TRUE) produce_item(item) sequence
sequence 1 / counts items produced
/ await(out, sequence - N) / wait until
buffer has room / enter_item(item) / insert
into buffer / advance(in) / inform
consumer /
35Event counters (producer-consumer)
- void consumer(void) int item, sequence
0 while(TRUE) sequence sequence
1 / count items produced /
await(in, sequence) / wait for item
/ remove_item(item) / take item from
buffer / advance(out) /
inform producer / consume_item(item)
36Monitors - high level synchronization constructs
- Semaphores and event_counters are too primitive
(low level) and are hard to program - Monitors are a special package of procedures
- Mutual exclusion constructs are generated by the
compiler. Internal data structures are invisible - Only one process is active in a monitor at the
same time - high level mutual exclusion - monitor sharedData
- int buffer
- public
- writeData(int byteNum)
-
- readData(int byteNum)
-
37Monitors - Condition variables
- Only one process is active in a monitor at the
same time - high level mutual exclusion - To enable synchronization
- Condition variables and operations on them wait
and signal - the monitor provides queuing for waiting
procedures - When one procedure waits and another signals,
the signaling procedure is inside the monitor !!!
- Operation signal must be either followed by
block() or exit_monitor, so that only one
procedure is active at one time
38Bounded-Buffer with Monitors
- monitor ProducerConsumer
- condition full, empty
- integer count
- procedure enter
- begin if count N then wait(full)
- enter_item
- count count 1
- if count 1 then signal(empty) end
- procedure remove
- begin if count 0 then wait(empty)
- remove_item
- count count - 1
- if count N - 1 then signal(full) end
- count 0
- end monitor
39Bounded-Buffer with Monitors (II)
- procedure producer
- begin while true do
- begin
- produce_item
- ProducerConsumer.enter
- end
- end
- procedure consumer
- begin while true do
- begin
- ProducerConsumer.remove
- consume_item end
- end
40Monitors - some comments
- Condition variables do not accumulate signals,
for later use - wait() must come before signal()
- Unlike sleep() and wakeup(), no race conditions,
because monitors have mutual exclusion - More complex implementation than semaphores,
compilers construct instead of system calls Up
Down - Problems...
- How to interpret nested monitors ?
- How to define wait, priority scheduling,
timeouts, aborts ? - How to Handle all exception conditions ?
- How to interact with process creation and
destruction ?
41Implementing Monitors with Semaphores
- semaphore mutex 1 / control access to
monitor / - cond c / c countsemaphore /
- void enter_monitor(void)
- down(mutex) / only one-at-a-time /
-
- void leave(void)
- up(mutex) / allow other processes in /
-
- void leave_with_signal(cond c) / cond
c is a struct / - if(c.count 0) up(mutex) / no waiting,
just leave.. / - else c.count--
- up(c.s)
-
- void wait(cond c) / block on a condition
/ - c.count / count waiting processes /
- up(mutex) / allow other processes /
- down(c.s) / block on the condition /
42Message Passing - avoiding former problems
- For several cpus with their own memories
semaphores cannot provide mutual exclusion - Implement synchronization by system calls
- Issues
- Sometimes an acknowledgement is needed
- A reliable address for processes (domains..)
- message ID to avoid duplication
- Authentication (validate the senders ID)
- Two main functions
- send(destination, message)
- receive(source, message) block while
waiting... - To avoid accessing a processs address space -
mailboxes
43Producer-consumer with Message Passing
- define N 100
- define MSIZE 4 / message size /
- typedef int message(MSIZE)
- void producer(void)
- int item
- message m / message buffer /
- while(TRUE) produce_item(item)
- receive(consumer, m) /wait for an empty /
- construct_message(m, item)
- send(consumer, m) / send item /
-
-
44Message passing (contnd.)
- void consumer(void)int item, imessage
mfor(i 0 i lt N i) send(producer, m)
/ send N empties / / Storage is up to the
OS / - while(TRUE) receive(producer, m) / get
message with item / extract_item(m,
item) send(producer, m) / send an empty
reply / consume_item(item)
45Messages - comments
- Unix pipes - a generalization of messages no
fixed size message (blocking receive) - Mailboxes take on the responsibility of
maintaining the buffer.. - Mailboxes can serve as an alternative address for
a process (instead of PID) - If no buffer is maintained by the system, then
every receive can only be run after a send call
this Rendezvous
46Equivalence Message passing with Semaphores
- Each process has an associated semaphore,
initially 0, on which to block while waiting for
a send or receive - A shared buffer area contains mailboxes, each one
containing an array of message slots - Slots are chained together, to keep their
receiving order, and there are counters of full
slots and of empty slots - Mailboxes also contain a pointer to queue of
unable_to_send_to processes and a pointer to
queue of unable_to_recieve_from - This enables an up operation for the waiting
process in a queue - The whole shared buffer must be protected by a
binary semaphore, so that only one process can
inspect or update the shared data structures
47Message passing with Semaphores
- Performing a send on a mailbox that contains at
least one empty slot - inserts a message, updates
counters and links - Performing a receive on an empty mailbox - enters
itself on the receive queue, up on mutex, down on
its own semaphore - When the receiving process is awakened - down on
mutex - Performing a send that has an empty slot - after
inserting the message, the sender checks the
waiting queue, if not empty removes the first
process and performs an up on its semaphore - The sender leaves the critical region following
the above up operation, and the mutex semaphore
is treated very similarly to the example
implementation of monitors - Performing a send to a full mailbox - enters
itself on the send queue, up on mutex, down on
its own semaphore
48Equivalence Semaphores with Message passing
- use a semaphore-process (mailbox) p
- p keeps the counter of the semaphore s
- down(s) - send(p,down(s))
- receive(p,ack)
- if s lt 0 p does not send an acknowledgement
- up(s) - send(p,up(s))
- if s lt 0 p sends the acknowledgement to a
selected process
49The dining (chinese) philosophers - problem
- define N 5
- void philosophers(int i)
-
- while(TRUE)
- think()
- take_stick(i) / left stick /
- take_stick(i1) N) / right stick /
- eat()
- put_stick(i)
- put_stick((i1) N)
-
-
- replace take_stick(i) by down(i) put_stick(I)
by up(I)
50The dining (chinese) philosophers - problem
- Each process needs two resources
- Every resource is mutual to two processes - I.e.
every pair of processes compete for a specific
resource - Every process can either be assigned two
resources or none at all - Every process that is waiting for its two
resources should sleep (be blocked) - Every process that releases its two resources
must wake-up the two competing processes for
these resources, if they are interested.
51Dining philosophers (soltn.)
- define N 5
- define LEFT (i-1) N
- define RIGHT (i1) N
- define THINKING 0
- define HUNGRY 1
- define EATING 2
- typedef int semaphore
- int stateN
- semaphore mutex 1
- semaphore sN / per each philosopher /
- void philosopher(int i)
-
- while(TRUE)
- think()
- pick_sticks(i)
- eat()
- put_sticks(i)
-
52pick_sticks(i) put_sticks(i) test(i)
- void pick_sticks(int i)
- down(mutex) / enter CS /
- statei HUNGRY
- test(i) / try for 2 sticks /
- up(mutex) / exit CS /
- down(si) / block if sticks were not
acquired../ -
- void put_sticks(int i)
- down(mutex)
- statei THINKING / finished eating../
- test(LEFT) / can left neighbour eat now ? /
- test(RIGHT) / .. RIGHT.. ? /
- up(mutex)
-
- void test(int i)
- if(statei HUNGRY stateLEFT ! EATING
stateRIGHT ! EATING) - statei EATING
- up(si)
53Chinese Philosophers - Monitor
- monitor diningPhilosophers
- condition selfN
- integer stateN
- procedure pick_sticks(i)
- begin statei HUNGRY
- test(i)
- if statei ltgt EATING then wait(selfi)
- end
- procedure put_sticks(i)
- begin
- statei THINKING
- test(LEFT)
- test(RIGHT)
- end
54Chinese Philosophers - Monitor (II)
- non-entry-procedure test(i)
- begin
- if stateLEFT ltgt EATING
- and stateRIGHT ltgt EATING
- and statei HUNGRY
- then begin
- statei EATING
- signal(selfi)
- end
- end
- for i 0 to 4 do statei THINKING
- end monitor
55Readers and Writers
- typedef int semaphoresemaphore mutex
1semaphore db 1int rc 0 / of
reading processes /void reader(void)
while(TRUE) down(mutex) / exclusive
access to rc / rc rc 1 if(rc
1) down(db) / first reader.. ? /
up(mutex) / release rc /
read_data_base() down(mutex) / exclusive
access to rc / rc rc - 1 if(rc
0) up(db) / last reader ? /
up(mutex) / release rc / void
writer(void) while(TRUE) down(db) /
get exclusive access / write_data_base()
up(db)
56Readers and Writers
- No reader is kept waiting, unless a writer has
already obtained the db semaphore - a second version of the readers-writers problem
requests that no writer is kept waiting once it
is ready - when a writer is waiting, no new
reader can start reading - In both cases processes may starve - writers in
the first version and readers in the second
version...
57Improve writers priority...
- typedef int semaphoresemaphore mutex 1,
mutex1 1semaphore db 1, rdb 1int rc
0, wc 0 / count readers and writers /void
reader(void) void writer(void)
while(TRUE) while(TRUE) down(rdb)
down(mutex1) - down(mutex) wc wc
1 rc rc 1
if(wc 1) down(rdb) if(rc 1)
down(db) up(mutex1)
up(mutex) down(db)
up(rdb) write_data_base() - read_data_base() up(db)
down(mutex) down(mutex1) rc rc -
1 wc wc -1 if(rc 0) up(db) if(wc
0) up(rdb) up(mutex)
up(mutex1)
58Readers-writers with Monitors
- Monitor reader_writer
- int numberOfReaders 0
- boolean busy FALSE
- condition okToRead, okToWrite
- public
- startRead
- if(busy (okToRead.queue)) okToRead.wait
- numberOfReaders numberOfReaders 1
- okToRead.signal
-
- finishRead
- numberOfReaders numberOfReaders - 1
- if(numberOfReaders 0) okToWrite.signal
-
59Readers-writers with Monitors (II)
- startWrite
- if((numberOfReaders ! 0) busy)
okToWrite.wait - busy TRUE
-
- finishWrite
- busy FALSE
- if(okToWrite.queue)
- okToWrite.signal
- else
- okToRead.signal
-
60..yet another synchronization problem - the
sleeping barber
- barber shop - one service provider many
customers - Finite capacity of shop - finite waiting queue
- One customer is served at one time
- Service provider, barber, sleeps when no
customers are waiting - Customer leaves if shop is full
- Customer sleeps while waiting in queue
- Use two semaphores - barber wait for customers
customers wait for barbers count queue length..
61..yet another synchronization problem - the
sleeping barber
- define CHAIRS 5
- typedef int semaphore
- semaphore customers 0
- semaphore barbers 0
- semaphore mutex 1
- int waiting 0
- void barber(void)
- while(TRUE)
- down(customers) / block if no customers /
- down(mutex) / access to waiting /
- waiting waiting - 1
- up(barbers) / barber is in.. /
- up(mutex) / release waiting /
- cut_hair()
62The sleeping barber
- void customer(void) down(mutex) / enter
CS / if(waiting lt CHAIRS) waiting
waiting 1 / increment waiting
/ up(customers) / wake up barber
/ up(mutex) / release waiting
/ down(barbers) / block for 0 barbers
/ get_haircut() else
up(mutex) / shop full .. leave /
63Deadlocks
- Deadlock of Resource Allocation
- Process A requests and gets Laser Printer
- Process B requests and gets Fast Modem
- Process A requests Fast Modem and blocks
- Process B requests Laser Printer and blocks
- Deadlock situation Neither process can move and
no process can release its allocated device
(Resource) - Comment both of the above resources (devices)
have exclusive access
64Resources
- Resources - Tapes, Disks, Printers, Database
Records, etc. - Some resources are non-preemptable (i.e. printer)
- Preemptable resources are easy (main memory)
- Resource allocation procedure
- Request
- Use
- Release
- Block process while waiting for Resources
65Defining Deadlocks
- A set of processes is deadlocked if each process
is waiting for an event that can only be caused
by another process in the set. - Necessary conditions for deadlock
- 1. Mutual exclusion resource used by only one
process - 2. Hold and wait process can request resource
while holding another resource - 3. No preemption only process can release
resource - 4. Circular wait 2 or more processes waiting for
resources held by other (waiting) processes
66Modelling deadlocks
- modelled by a directed graph (resource graph)
- Requests and assignments as directed edges
- Processes and Resources as vertices
- Cycle in graph means deadlock
F
P
A
S
R
Q
B
M
67the occurance of deadlocks
68Dealing with Deadlocks
- Possible Strategies
- Prevention
- structurally negate one of the four necessary
conditions - Avoidance
- allocate resources carefully, so as to avoid
deadlocks - Detection and recovery
- Do nothing (Ostrich algorithm)
- deadlocks are rare and hard to tackle... do
nothing - Unix - process table with 1000 entries and 100
processes each requesting 20 FORK calls...
deadlock - users prefer a rare deadlock on frequent refusal
of FORK
69Deadlock prevention
- Attack one of the 4 necessary conditions
- 1. Mutual exclusion
- Minimize exclusive allocation of devices
- Use spooling (not good for all devices - Tapes
Process Tables) may fill up spools (disk space
deadlock)... - 2. Hold and Wait
- Request all resources immediately (before
execution) - Problem not known initially, inefficient
- or
- to get a new resource, free everything, then
request everything again (including new resource)
70Attack one of the 4 necessary conditions
- 3. No preemption
- causes incorrect execution...
- ... without the process knowing it
- 4. Circular wait condition
- Allow holding only single resource (bad idea)
- Number resources, allow requests only in
ascending order - Request only resources numbered higher than
anything currently held - Not a workable solution - may have no solution
71Deadlock Avoidance
- System grants resources only if it is safe
- basic assumption maximal request per process is
known - Example 2 processes and 2 devices (Printer
Plotter)
72Safe and Unsafe states - 1 resource
- safe states
- Not deadlocked
- There is a way to satisfy all possible future
requests
73Bankers Algorithm (single resource)
- Simulate allocation of resources
- Bankers Algorithm (Dijkstra 1965)
- 1. Pick a process that can terminate (enough free
resources) - 2. Free all its resources (simulation)
- 3. Mark process terminated
- 4. If all processes marked, report safe, halt
- 5. If no process can terminate, report unsafe,
halt - 6. Go to step 1.
74Multiple resources of each kind
- Assume n processes and m resource classes
- Use four arrays
- Current allocation matrix Cn x m
- Request matrix Rn x m
- Existing resources vector Em
- Available resources vector Am
- Detect deadlocks by comparing vectors
- for 1 j m Cij Aj Ej
- A B if for 0 i m Ai
Bi
75Bankers Algorithm (multiple resources)
- 1. Look for process Pi for which the row i of R
is less than A (process can proceed). - 2. If found, add row i of C (i.e. all its
resources) to A, mark Pi, and go to step 1.,
else terminate. - 3. Repeat steps 1 and 2 until either all
processes are marked terminated, which means
safe, or until a deadlock occurs, which means
unsafe.
76Safety of states with multiple resources
- Granting a printer to B leads to a safe state
- Now, granting the last printer to E leads to
deadlock
77Deadlock Avoidance is not practical
- Maximum resource request per process is not known
initially - moreover, its point in time is also unknown
- Resources may disappear
- some devices leave the available pool (break
down) - New processes may appear
- the system is dynamic and processes are born and
die at any moment
78Deadlock Detection and Recovery
- Find if a deadlock exists
- if there is, which processes and resources
- Detection detect cycles in resource graph
- Algorithm DFS node and arc marking
79A Resource Allocation Graph
80Resource Allocation Graph With A Deadlock
81A Cycle But No Deadlock
82Basic Facts
- If graph contains no cycles ? no deadlock.
- If graph contains a cycle ?
- if only one instance per resource type, then
deadlock. - if several instances per resource type,
possibility of deadlock.
83deadlock detection - 4 resource-types
- Resources - (Tape-drives Modems Printers
CD-ROMs) - Existing resources - E (4 2 3 1)
- Available resources - A (2 1 0 0)
- Current allocation
- Request matrix
0
0
0
1
0
0
1
2
0
1
2
0
2
1
0
0
1
1
0
0
2
1
0
0
84When should the system check for deadlock ?
- For every request instance - too expensive
- every k minutes...
- whenever cpu utilization drops strongly (good
sign of deadlock..)
85Recovery
- Preemption - possible in some rare cases
- temporarily take a resource away from its current
owner - Rollback - possible with checkpointing
- keep former states of processes (checkpoints) to
enable release of resources and going back - Killing a process - easy way out, may cause
problems in some cases, depending on process
being rerunable - Bottom line hard to recover from deadlock,
avoid it
86Eaxmple - deadlocks in DBMSs
- For database records that need locking first and
then updating - Deadlocks occur frequently because records are
dynamically requested by competing processes - DBMSs, therefore, need to employ deadlock
detection and recovery procedures - Recovery is possible - transactions are
checkpointed - release everything and restart - Not useful for network messages sent and
received, for example - cannot be terminated and
started over safely
87Additional issues of deadlock
- Deadlocks may occur with respect to actions of
processes, not resources - waiting for semaphores - Starvation can result from a bad allocation
policy (such as smallest-file-first, for
printing) and for the starved process will be
equivalent to a deadlock (cannot finish running) - Summary of deadlock treatment
- Avoid (be only in safe states)
- Detect and recover
- Prevent by using an allocation policy or
conditions - Ignore problem
88Detection - extract a cycle
- 1. Process A holds R and requests S
- 2. Process B holds nothing and requests T
- 3. Process C holds nothing and requests S
- 4. Process D holds U and requests S and T
- 5. Process E holds T and requests V
- 6. Process F holds W and requests S
- 7. Process G holds V and requests U
89Find cycles
- For each node, N, in the graph, perform the
following 5 steps with N as starting node - 1. Initialize L to the empty list and designate
all arcs as unmarked - 2. Add the current node to the end of L and check
if the node appears twice in L. If it does, the
graph contains a cycle, terminate. - 3. If there are any unmarked arcs from the given
node, go to 4., if not go to 5. - 4. Pick any unmarked outgoing arc and mark it.
Follow it to the new current node and go to 2. - 5. We have reached a deadend. Go back to the
previous node, make it the current node and go to
2. If the node is the initial node, there are no
cycles in the graph, terminate