Outline 0024 Spring 2010 10 :: 2 Recall 0024 Spring 2010 10 - - PowerPoint PPT Presentation
Outline 0024 Spring 2010 10 :: 2 Recall 0024 Spring 2010 10 - - PowerPoint PPT Presentation
Outline 0024 Spring 2010 10 :: 2 Recall 0024 Spring 2010 10 :: 3 0024 Spring 2010 10 :: 4 0024 Spring 2010 10 :: 5 Dekker: core classes class Insist { private
– 10 :: 2 – 0024 Spring 2010
Outline
– 10 :: 3 – 0024 Spring 2010
Recall
– 10 :: 4 – 0024 Spring 2010
– 10 :: 5 – 0024 Spring 2010
– 10 :: 6 – 0024 Spring 2010
Dekker: core classes
class Insist { private volatile int winner; void setWinner(int id) { winner = id; } int getWinner() { return winner;} } class Turn { private volatile int flag = 1; private final Insist insist; Turn (Insist a) { insist = a; } // continued
– 10 :: 7 – 0024 Spring 2010
Dekker: core classes, part 2
void request() { flag = 0;} void free() { flag = 1; } int read() { return flag; } void setWinner(int id) { insist.setWinner(id); } int getWinner() { return insist.getWinner(); } }
– 10 :: 8 – 0024 Spring 2010
Worker
- public void run() {
int nextid; if (myid==0) {nextid = 1;} else {nextid=0;}; while (true) { mysignal.request(); while (true) { if (othersignal.read() == 1) break; if (mysignal.getWinner() == nextid) { mysignal.free(); while (true) { if (mysignal.getWinner() == myid) break; }; // other thread won 1st round mysignal.request(); } }
– 10 :: 9 – 0024 Spring 2010
Worker, continued
// critical section mysignal.free(); mysignal.setWinner(nextid); } // end loop } }
– 10 :: 10 – 0024 Spring 2010
Master
class Dekker { public static void main(String[] args) { Insist arbiter = new Insist(); Turn gate0 = new Turn(arbiter); Turn gate1 = new Turn(arbiter); Thread t1 = new Thread(new Worker(0,gate0,gate1)); Thread t2 = new Thread(new Worker(1,gate1,gate0)); t1.start(); t2.start(); } }
– 10 :: 11 – 0024 Spring 2010
Worker 0
public void run() { while (true) { A1: s0.request(); while (true) { A2: if (s1.read() == 1) break; A3: if (s0.getWinner() == 1) { s0.free(); while (true) { if (s0.getWinner() == 0) break; }; // worker 1 won 1st round s0.request(); } // end check if worker 1 insists } A4: // critical section s0.free(); s0.setWinner(1); } // end loop } // end run
– 10 :: 12 – 0024 Spring 2010
Worker 1
public void run() { while (true) { s1.request(); while (true) { if (s0.read() == 1) break; if (s1.getWinner() == 0) { s1.free(); while (true) { if (s1.getWinner() == 1) break; }; // worker 0 won 1st round s1.request(); } // end check if worker 0 insists } // critical section s1.free(); s1.setWinner(0); } // end loop } // end run
– 10 :: 13 – 0024 Spring 2010
Can both threads enter the critical section?
– 10 :: 14 – 0024 Spring 2010
– 10 :: 15 – 0024 Spring 2010
Temporal logic
We want to show that there is no starvation. Must reason that an event (start of critical section) will happen eventually. E.g., for worker 0 we must show that once A1 is executed eventually A4 is reached
- Must show the same for Thread B …
– 10 :: 16 – 0024 Spring 2010
Worker 0
public void run() { while (true) { A1: s0.request(); while (true) { A2: if (s1.read() == 1) break; A3: if (s0.getWinner() == 1) { s0.free(); while (true) { if (s0.getWinner() == 0) break; }; // worker 1 won 1st round s0.request(); } // end check if worker 1 insists } A4: // critical section s0.free(); s0.setWinner(1); } // end loop } // end run
– 10 :: 17 – 0024 Spring 2010
Notation
p means “p is always true” p means “p is eventually true” Shorthand to save us typing
– 10 :: 18 – 0024 Spring 2010
Notation
p means “p is always true”
After p turns true we read the value “true” whenever we want
to
q means “q is eventually true”
No statement how long q will remain true.
Often we must show p
Eventually p turns true and will remain true as long as we
care to check it
Example:
p , q ⇒ ( p q )
– 10 :: 19 – 0024 Spring 2010
Absence of starvation
– 10 :: 20 – 0024 Spring 2010
Lemma 1
– 10 :: 21 – 0024 Spring 2010
– 10 :: 22 – 0024 Spring 2010
Lemma 2
– 10 :: 23 – 0024 Spring 2010
Proof of freedom from starvation
– 10 :: 24 – 0024 Spring 2010
Proof, continued
– 10 :: 25 – 0024 Spring 2010
Proof, continued
– 10 :: 26 – 0024 Spring 2010
Semaphores
Programming with critical sections is hard (impossible).
- Better abstractions are needed.
We have seen the event queues in Java We now look at another primitive
More comfortable than critical sections based on Dekkers
solution yet still not too complicated
Idea: a semaphore S is an integer-valued variable with two operations
P(S): if S>0 then S:= S-1
else suspend thread
V(S): if (there are suspended threads) then wake one of them
else S = S+1
– 10 :: 27 – 0024 Spring 2010
Semaphores - operations
P: wait, V: signal P(S) and V(S) are atomic
No interruption
S must be given a non-negative starting value (S0) V(S) wakes up one thread -- no way to specify which
- ne
Binary semaphores: S is intitalized with 1
Legal values are 0 and 1
– 10 :: 28 – 0024 Spring 2010
Semaphore invariants
i) S 0 ii) S = S0 + #V(S) - #P(S)
– 10 :: 29 – 0024 Spring 2010
Semaphore use
Its easy to make programming mistakes: forget a V(S) and no other thread will be able to make progress
Other threads remain suspended on S forever
Model of a program
- loop {
non_critical_section
- P(S)
- critical section
V(S) }
– 10 :: 30 – 0024 Spring 2010
Properties
Mutual exclusion
Let S be a binary semaphore (i.e. S0 = 1) Proof: Let #T be the number of threads in their critical
- sections. Show that (#T + S == 1) is invariant.
Since S 0 it follows that #T 1. Show that (#T + S == 1) is invariant:
#T == #P(S) - #V(S) S == 1 + #V(S) - #P(S) S == 1 - #T #T + S == 1
Absence of deadlock Absence of starvation of a thread
– 10 :: 31 – 0024 Spring 2010
N threads
Solution with semaphores works for N threads
Our proof did not rely on the number of threads
Recall our different kinds of fairness - corresponding classes of semaphores
– 10 :: 32 – 0024 Spring 2010
Semaphores
Blocked-set semaphore: (Model used so far) V(S) wakes up one of the suspended threads Blocked-queue semaphore: Suspended threads are kept in a FIFO queue, wake up in order of suspension
- P(S): if (S >0) S-- else {append to tail of queue}
V(S): if (∃ suspended threads) {wake up thread at head of
queue, remove it from queue} else S++
Busy-wait semaphore: Value of S tested in busy wait loop (the if-stmt executes atomically but different threads may execute their if-stmt in interleaved manner)
P(S): while (true) {
if (S>0) { S=S-1; break;} }
V(S): S++
– 10 :: 33 – 0024 Spring 2010
Properties
For a busy-wait semaphore, starvation is possible.
– 10 :: 34 – 0024 Spring 2010
“Dining Philosophers”
N philosophers (e.g., N==5) N (5) study rooms 1 dining room 1 dining table with N (5) bowls and N (5) forks
Bowls and forks remain on table
Simple life of a philosopher:
while (true) { // think // eat }
– 10 :: 35 – 0024 Spring 2010
Rules
A philosopher eats only if s/he has two forks
Needs those to heap pasta into the bowl Once a philosopher has a fork, s/he hangs on to it until s/he
can eat
No two philosophers may hold the same fork simultaneously Your task: organize the life of the philosophers No deadlock No individual starvation Efficient behavior (access to food) in the absence of contention
– 10 :: 36 – 0024 Spring 2010
Dining table
– 10 :: 37 – 0024 Spring 2010
Idea
– 10 :: 38 – 0024 Spring 2010
Semaphore solution 1
Semaphore [] fork = new Semaphore[5]; // Default semaphore is binary // Philosopher I (0 I 4) while (true) { // think fork[i].p(); // right fork fork[mod(i+1,5)].p(); // left fork // eat fork[i].v(); fork[mod(i+1,5)].v(); }
– 10 :: 39 – 0024 Spring 2010
Problem: Deadlock
– 10 :: 40 – 0024 Spring 2010
Deadlock avoidance
Limit number of philosophers in dining room
additional semaphore to control room occupancy
Semaphore [] fork = new Semaphore[4]; Semaphore room = new Semaphore(4); // init to 4 // Philosopher i: while (true) { // think room.p(); fork[i].p(); fork[mod(i+1,5)].p(); // eat fork[i].v(); fork[mod(i+1,5)].v(); room.v(); }
– 10 :: 41 – 0024 Spring 2010
Another solution
Semaphore [] fork = new Semaphore[4]; // init // Philosopher 0, 1, 2, 3: // unchanged // Philosopher 4: while (true) { // think fork[0].p(); fork[4].p(); // eat fork[4].v(); fork[0].v(); }