Upload
melvyn-manning
View
222
Download
0
Embed Size (px)
Citation preview
CPS110: Deadlock
Landon Cox
February 4, 2009
Concurrency so far
Mostly tried to constrain orderings Locks, monitors, semaphores
It is possible to over-constrain too A must run before B B must run before A
This can lead to deadlock
Definitions
Resource Thing needed by a thread to do its job Threads wait for resources E.g. locks, disk space, memory, CPU
Deadlock Circular waiting for resources Leaves threads unable to make
progress
Example deadlock
Both CPS108 and CPS110 are full You want to switch from 110 to 108 Someone else wants to switch from 108 to
110 Algorithm for switching
Wait for spot in new class to open up Add new class Drop old class
Problem: must add before dropping
Deadlock and starvation
Deadlock starvation Starvation = one process waits
foreverThread A Thread Block (x) lock (y)lock (y) lock (x)… …unlock (y) unlock(x)unlock (x) unlock(y)
Can deadlock occur?
Deadlock and starvation
Deadlock starvation Starvation = one process waits
foreverThread A Thread Block (x)
lock (y)lock (y) // wait for B
lock (x) // wait for A
Can deadlock occur?Will deadlock always occur?
Common thread work pattern
Has anyone taken CPS116 (databases)? This is called “two-phase” locking Ensures “conflict-serializability” Still deadlock-prone
Phase 1. while (not done) { get some resources (block if necessary) work // assume finite }Phase 2. release all resources
Dining philosophers
BB
AA
CCDD
EE
Philosopher algorithm1) Wait for right chopstick2) Pick up right chopstick3) Wait for left chopstick4) Pick up left chopstick5) Eat6) Put both chopsticks down
How can deadlock occur?
Conditions for deadlock
1. Limited resource Not enough for all threads simultaneously
2. Hold-and-wait Hold one resource, while waiting for
another
3. No pre-emption Cannot force threads to give up resources
4. Circular chain of requests
Circular chain of requests
Arrows Thread resource it’s waiting for Resource thread that’s holding it
Thread AThread A
Thread BThread B
Resource 2Resource 2Resource 1Resource 1
Thread B acquires Resource 1Thread B waits for Resource 2
Thread A acquires Resource 2Thread A waits for Resource 1
Called a wait-for graph
Deadlock
What should we do about them?1.Ignore them
Common OS-level solution for programs (OS has no control over user programs)
2.Detect-and-fix3.Prevent
Detect-and-fix
First part: detect This is easy; just scan the wait-for graph
Second part: fix1.Kill first thread, take back resources by force
Why might this be unsafe? Can expose inconsistent state
2.Roll-back actions of 1 or more thread, retry Often used in databases Not always possible (some actions can’t be undone)
E.g. can’t unsend a network message
Detect-and-fix
Retrying during fix phase can be tricky If holding R and will wait for L, drop R and try again.
BB
AA
CCDD
EE
What could happen? Everyone picks up R Everyone drops R Everyone picks up R Everyone drops R (and so on)This is called “livelock.”
Detect-and-fix
Retrying during fix phase can be tricky If holding R and will wait for L, drop R and try again.
BB
AA
CCDD
EE
How to prevent livelock? Choose a winner.How to choose a winner? First to start/pick up?What if we have priorities? (called “priority inversion”) e.g. Queen waiting for jokerShould Queen always win? No, could starve the joker
Deadlock prevention
Idea: remove one of four pre-conditions
1.Make resources unlimited Best solution, but often impossible Can still increase number, reduce
likelihood (larger 108 and 110 classes) Not clear this works for locks
Deadlock prevention
2. Eliminate hold-and-wait Idea: move resource acquisition to beginning
Two ways to avoid holding while waiting
Phase 1a. get all resourcesPhase 1b. while (not done) { work // assume finite }Phase 2. release all resources
Eliminating hold-and-wait
1. Wait for everything to be free, then grab them all at oncePhilosopher algorithm
lock while (left chopstick busy || right chopstick busy) { wait } pick up right chopstick pick up left chopstick unlock eat lock drop chopsticks unlock
Any potential problems?Can induce starvation (neighbors alternate eating).
Eliminating hold-and-wait
2. If you find a resource busy, drop everything, and try againPhilosopher algorithm
lock while (1) { while (right chopstick busy) { wait } pick up right chopstick if (left chopstick busy) { drop right chopstick } else { pick up left chopstick break } } unlock eat lock drop chopsticks unlock
Issues?Must predict what you need in advance.
Hold reservations longer than neededRequires changes to applications.
Deadlock prevention
3. Enable pre-emption Can pre-empt the CPU (context switch) Can pre-empt memory (swap to disk) Not everything can be pre-empted Can locks be pre-empted?
Probably not Must ensure that data is in consistent state
Deadlock prevention
4. Eliminate circular chain of requests
How can we get rid of these cycles? Impose an ordering on resource acquisition E.g. must always acquire A before B
In dining philosophers? Number chopsticks Pick up lower-numbered chopstick first
Dining philosophers
BB
AA
CCDD
EE
11 22
33
4
55
Philosopher algorithm1) Wait for lower chopstick2) Pick up lower chopstick3) Wait for higher chopstick4) Pick up higher chopstick5) Eat6) Put both chopsticks down
Try to create a deadlock
Universal ordering
Why does this work? At some point in time
T holds highest-numbered acquired resource T is guaranteed to make progress. Why?
If T needs a higher-numbered resource, it must be free If T needs a lower-numbered resource, it already has it
If T can make progress, it will eventually release all of its resources
What if another thread acquires a higher-numbered resource?
They just become T (in which case, the same reasoning as above holds)
Dining philosophers
BB
AA
CCDD
EE
11 22
33
4
55
Philosopher algorithm1) Wait for lower chopstick2) Pick up lower chopstick3) Wait for higher chopstick4) Pick up higher chopstick5) Eat6) Put both chopsticks down
What if E only needs one chopstick?Only have trouble if E acquires lower-numbered chopstick before 5.(but this is a violation of our rule)
Deadlock avoidance
Issue with imposing global orderings Must change the application
Common technique Requires programming discipline
Course administration
Project 1 Due February 18th (two weeks) 6 groups are done with 1d No one has submitted 1t yet (!)
Should be done with 1d by end of the week 1t is a lot more work, don’t keep putting it off!
Compiling g++ -o disk disk.cc thread.o
Course administration Remember to work on your thread library test suite too For each of your test cases
Compare output of your library with thread.o
Writing test cases Read through spec
Write test cases to stress each required part E.g. lock() blocks if lock is already held Use yield() to create the right interleavings
Read through your code Write test cases to exercise all lines of code E.g. each clause of an if/else statement
Micro-tests are better for debugging than macro-tests
Banker’s algorithm
Like acquiring all resources first (but more efficient)
Phase 1a. state max resources neededPhase 1b. while (not done) { get some resources (blocking if not SAFE) work // assume finite }Phase 2. release all resources
Comparing banker’s algorithm
Original Acquired resources if available (deadlock)
Previous solution (no “hold-and-wait”) Acquired all resources or none Must acquire max resources to do work
All threads doing work own their max Thus, all threads doing work can complete
Banker’s algorithm
Give out resources at request time (1b)
Request granted if it is safe Can grant max requests of all threads in some
sequential order
Sequential order One thread gets its max resources, finishes, and
releases its resources Another thread gets its max resources, finishes, and
releases, etc
Phase 1a. state max resources neededPhase 1b. while (not done) { get some resources (blocking if not SAFE) work // assume finite }Phase 2. release all resources
Example
Bank Has $6000 to loan
Customers Establish credit limits (max
resources) Borrow money (up to their limit) Return all money at the end
Example: Solution 1
Bank gives money on request, if available
For example Ann asks for credit line of $2000 Bob asks for credit line of $4000 Cat asks for credit line of $6000
Can bank approve each of these lines? (assuming it gives money, if available)
Example: Solution 1
No. Consider: Ann takes out $1000 (bank has $5000) Bob takes out $2000 (bank has $3000) Cat takes out $3000 (bank is empty)
Bank has no money Ann, Bob, and Cat could all ask for $
None would be able to finish (deadlock)
Example: Solution 1
This only works if we wait to approve credit lines For example
Ann asks for credit line of $2000 Bank approves
Bob asks for credit line of $4000 Bank approves
Cat asks for credit line of $6000 Bank must make Cat wait until Ann or Bob finish
Sum of all max resource needs of all current threads Must not exceed the total resources
Example: Solution 2
Bank says ok to all credit line requests Customers may wait for resources Bank ensures no deadlocks
For example Ann asks for credit limit of $2000 Bob asks for credit limit of $4000 Cat asks for credit limit of $6000 Bank approves all credit limits
Example: Solution 2
Ann takes out $1000 (bank has $5000) Bob takes out $2000 (bank has $3000) Cat wants to take out $2000
Is this allowed? Bank would be left with $1000 Ann would still be guaranteed to finish
(could take out another $1000) On finish, bank would have $2k This is enough to ensure that Bob can finish
Example: Solution 2
Ann takes out $1000 (bank has $5000) Bob takes out $2000 (bank has $3000) Cat wants to take out $2500
Is this allowed? Bank would be left with $500 Can’t guarantee that any threads will
finish
Banker’s algorithm
Allows resources to be overcommitted How can we apply this to dining philosophers?
Put all chopsticks in the middle of the table Max resource need for each philosopher is 2 Grant requests, unless
There is only one chopstick left and nobody has 2
Nice algorithm, but few people use it. Why? You rarely know what you’ll need in advance Doesn’t really make sense for locks (no “generic
lock”)