Upload
harvey
View
29
Download
1
Embed Size (px)
DESCRIPTION
Concurrency , Dining Philosophers Lecture 14. COMP 201. What is a Concurrent Program?. A sequential program has a single thread of control. - PowerPoint PPT Presentation
Citation preview
Slide 1
Concurrency, Dining Philosophers
Lecture 14
COMP 201
Slide 2
What is a Concurrent Program?
A sequential program has a single thread of control.
A concurrent program has multiple threads of control allowing it perform multiple computations in parallel and to control multiple external activities which occur at the same time.
Slide 3
Why Concurrent Programming?
• Performance gain from multiprocessing hardware
– parallelism.
• Increased application throughput
– an I/O call need only block one thread.
• Increased application responsiveness
– high priority thread for user requests.
• More appropriate structure
– for programs which interact with the environment,
control multiple activities and handle multiple events.
Slide 4
Do I need to know about concurrent programming?
Therac - 25 computerised radiation therapy machine
Concurrent programming errors contributed to accidents causing deaths and serious injuries.
Mars Rover
Problems with interaction between concurrent taskscaused periodic software resets reducing availability forexploration.
Concurrency is widespread but error prone.
Slide 5
Deadlock error
Slide 6
Deadlock
Concepts: system deadlock: no further progress
four necessary & sufficient conditions
Models: deadlock - no eligible actions
Practice: blocked threadsAim: deadlock avoidance - to design systems where deadlock cannot occur.
Slide 7
Deadlock: four necessary and sufficient conditions
Serially reusable resources:
the processes involved share resources which they use under mutual exclusion.
Incremental acquisition:
processes hold on to resources already allocated to them while waiting to acquire additional resources.
No pre-emption:
once acquired by a process, resources cannot be pre-empted (forcibly withdrawn) but are only released voluntarily.
Wait-for cycle:
a circular chain (or cycle) of processes exists such that each process holds a resource which its successor in the cycle is waiting to acquire.
Slide 8
Wait-for cycle
A
B
CD
E
Has A awaits B
Has B awaits C
Has C awaits DHas D awaits E
Has E awaits A
Slide 9
Dining PhilosophersFive philosophers sit around a circular table. Each philosopher spends his life alternately thinking and eating. In the centre of the table is a large bowl of spaghetti. A philosopher needs two forks to eat a helping of spaghetti.
0
1
23
40
1
2
3
4
One fork is placed between each pair of philosophers and they agree that each will only use the fork to his immediate right and left.
Slide 10
Dining Philosophers - model structure diagram
Each FORK is a shared resource with actions get and put.
When hungry, each PHIL must first get his right and left forks before he can start eating.
phil[4]:PHIL
phil[1]:PHIL
phil[3]:PHIL
phil[0]:PHIL
phil[2]:PHIL
FORK FORK
FORK
FORK FORK
lef tright
right
right
right
lef t
lef t
right
lef t
lef t
Slide 11
Dining Philosophers
Slide 12
Dining Philosophers
Slide 13
ASML specification
• A number of philosophers are sitting around a table.
• Each one has a fork to the left and a fork to the right.
• We model forks as structures with a unique field index.
structure Fork index as Integer
Slide 14
Abstract class Philosopher• Philosophers are modelled as having a unique index, what state
they are currently in and as being capable of two methods:
– reporting whether they can make a state change (canMove) and
– performing a state change (move).
• Because the value of the field status can change, a Philosopher is a class and not a structure.
abstract class Philosopher var status as State = Thinking
index as Integer
canMove() as Boolean
move()
Slide 15
For simplicity we assume that there are a fixed number (four) of true philosophers (called simply philosophers below) and one fake philosopher called nobody.
numPhilosophers as Integer = 4 nobody as Philosopher = undef
Likewise we have four forks.
numForks as Integer = numPhilosophers forks as Set of Fork = { Fork(i) | i ∈ {1..numForks} }
The fork to the left of a philosopher has the same index as the philosopher. The fork to the right of a philosopher has the next higher index (modulo the number of philosophers).
left(p as Philosopher) as Fork return Fork(p.index)
right(p as Philosopher) as Fork return Fork(p.index mod numPhilosophers + 1)
Slide 16
Philosopher’s lifecycle • A thinking philosopher has no forks.
(Who needs a fork to think?) • A thinking philosopher may become hungry. • A hungry philosopher tries to grab the fork to the left
and thus becomes a hungry philosopher with a left fork.
• But one fork is not enough: a philosopher starts eating only upon obtaining both forks.
• The fork to right can be obtained only if it is not being used.
• From eating, there is only one place to go: back to thinking after putting down both forks.
Slide 17
A successful philosopher's lifecycle is this
Thinking Hungry
HungryWithLeftForkEating
enum State Thinking; Hungry; HungryWithLeftFork; Eating
Initially nobody has a fork.
var holder as Map of Fork to Philosopher = { f ↦
nobody | f ∈ forks }
Slide 18
Greedy Philosophers
• A greedy philosopher never puts down a fork until (s)he has eaten and starts thinking.
• This can lead to deadlock.
• The behaviour has been made a little fancier by introducing a random amount of thinking and eating for a fixed amount of time– a thinking philosopher will remain thinking about 80
percent of the time.
Slide 19
class greedyPhilosopher extends Philosopher
var bites as Integer = 0
move()
match status Thinking : if (any i | i ∈ {1..10}) < 3 then // usually they
prefer to think status := Hungry Hungry : if holder(left(me)) = nobody then
holder(left(me)) := me status :=
HungryWithLeftFork HungryWithLeftFork : if holder(right(me)) = nobody
then holder(right(me)) := me status := Eating bites := 3 // the
fixed number of bites Eating : if bites > 0 then bites := bites - 1
else holder(left(me)) := nobody holder(right(me)) := nobody
status := Thinking
Slide 20
Extracting the conditions from the method move yields the function canMove which indicates whether the philosopher
can make a state change or not.
class greedyPhilosopher...
canMove() as Boolean
return status = Thinking ∨ (status = Hungry ∧ holder(left(me)) = nobody)
∨ (status = HungryWithLeftFork ∧ holder(right(me)) = nobody) ∨ status = Eating
asString() as String
return "Greedy #" + index
Slide 21
Generous Philosophers
• A generous philosopher does not insist on following a successful philosophical life.
• After picking up the left fork, but finding that the right fork is not available, a generous philosopher drops the left fork and goes back to think some more.
• So if all philosophers are generous, then there is no deadlock, but starvation is possible.
Slide 22
class generousPhilosopher extends Philosopher
move()
match status Thinking : status := Hungry Hungry : if holder(left(me)) = nobody then
holder(left(me)) := me status := HungryWithLeftFork
HungryWithLeftFork : if holder(right(me)) = nobody then
holder(right(me)) := me status := Eating
else // someone else is holding the right fork put // the left one down and try again another time holder(left(me)) := nobody status := Thinking Eating : holder(left(me)) := nobody holder(right(me)) := nobody status := Thinking
Slide 23
Notice that the conditions which indicate whether a generous
philosopher can make a state change or not are more liberal than those for greedy philosophers.
class generousPhilosopher...
canMove() as Boolean
return status = Thinking ∨ (status = Hungry ∧ holder(left(me)) =
nobody) ∨ status = HungryWithLeftFork ∨ status = Eating
asString() as String return "Generous #" + index
Slide 24
A successful generous philosopher's lifecycle is this
Thinking Hungry
HungryWithLeftForkEating
Slide 25
The Scheduler
Here is one possible scheduler: – From the set that it is given,
• it chooses a philosopher that can make a state transition and then
• fires the state transition.
– If no philosopher can make a step, then • the system is deadlocked and
• an exception is thrown.
Slide 26
structure deadlockException implements RuntimeException
message as String describe() as String
return "Deadlock: " + message
schedule(ps as Set of Philosopher, i as Integer)
choose p ∈ ps where p.canMove()
step currentStatus = p.status p.move()
step WriteLine(p + " was " + currentStatus + ", but now is " + p.status) ifnone
throw deadlockException("after " + i + " steps")
Slide 27
The Main Program
• The main program tries to run the above schedule 1000 times, and is ready to catch the exception thrown if the system deadlocks.
• You may choose which type of philosopher to schedule, just comment out one of the "greedy" or "generous" lines in the code.
Slide 28
Main()
phils = { new greedyPhilosopher(i) as Philosopher | i ∈ [1..numPhilosophers] }
//phils = { new generousPhilosopher(i) as Philosopher | i ∈ [1..numPhilosophers] }
try step foreach i ∈ [1..1000]
schedule( phils, i )
catch
d as deadlockException : WriteLine(d.describe())
The Main Program (code)
Slide 29
Summary• Concepts
– deadlock: no futher progress
– four necessary and sufficient conditions:
• serially reusable resources
• incremental acquisition
• no preemption
• wait-for cycle
• Models
– no eligable actions (analysis gives shortest path trace)
• Practice
– blocked threads
Aim: deadlock avoidance - to design systems where deadlock cannot occur.