Concurrency , Dining Philosophers Lecture 14

29
Slide 1 Concurrency, Dining Philosophers Lecture 14 COMP 201

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

Transcript of Concurrency , Dining Philosophers Lecture 14

Page 1: Concurrency , Dining Philosophers Lecture 14

Slide 1

Concurrency, Dining Philosophers

Lecture 14

COMP 201

Page 2: Concurrency , Dining Philosophers Lecture 14

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.

Page 3: Concurrency , Dining Philosophers Lecture 14

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.

Page 4: Concurrency , Dining Philosophers Lecture 14

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.

Page 5: Concurrency , Dining Philosophers Lecture 14

Slide 5

Deadlock error

Page 6: Concurrency , Dining Philosophers Lecture 14

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.

Page 7: Concurrency , Dining Philosophers Lecture 14

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.

Page 8: Concurrency , Dining Philosophers Lecture 14

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

Page 9: Concurrency , Dining Philosophers Lecture 14

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.

Page 10: Concurrency , Dining Philosophers Lecture 14

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

Page 11: Concurrency , Dining Philosophers Lecture 14

Slide 11

Dining Philosophers

Page 12: Concurrency , Dining Philosophers Lecture 14

Slide 12

Dining Philosophers

Page 13: Concurrency , Dining Philosophers Lecture 14

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

Page 14: Concurrency , Dining Philosophers Lecture 14

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

Page 15: Concurrency , Dining Philosophers Lecture 14

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)

Page 16: Concurrency , Dining Philosophers Lecture 14

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.

Page 17: Concurrency , Dining Philosophers Lecture 14

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 }

Page 18: Concurrency , Dining Philosophers Lecture 14

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.

Page 19: Concurrency , Dining Philosophers Lecture 14

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

Page 20: Concurrency , Dining Philosophers Lecture 14

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

Page 21: Concurrency , Dining Philosophers Lecture 14

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.

Page 22: Concurrency , Dining Philosophers Lecture 14

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

Page 23: Concurrency , Dining Philosophers Lecture 14

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

Page 24: Concurrency , Dining Philosophers Lecture 14

Slide 24

A successful generous philosopher's lifecycle is this

Thinking Hungry

HungryWithLeftForkEating

Page 25: Concurrency , Dining Philosophers Lecture 14

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.

Page 26: Concurrency , Dining Philosophers Lecture 14

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

Page 27: Concurrency , Dining Philosophers Lecture 14

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.

Page 28: Concurrency , Dining Philosophers Lecture 14

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)

Page 29: Concurrency , Dining Philosophers Lecture 14

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.