implementing critical sections in software hard
play

Implementing Critical Sections in Software Hard The following - PDF document

Implementing Critical Sections in Software Hard The following example will demonstrate the difficulty of providing mutual exclusion with memory reads and writes Hardware support is needed The code must work all of


  1. Implementing ¡Critical ¡Sections ¡in ¡Software ¡Hard ¡ The following example will demonstrate the difficulty of providing mutual exclusion with memory reads and writes Ø Hardware support is needed The code must work all of the time Thre read S d Synchro ronization: Ø Most concurrency bugs generate correct results for some Too M Much M Milk interleavings Designing mutual exclusion in software shows you how to think about concurrent updates Ø Always look for what you are checking and what you are updating Ø A meddlesome thread can execute between the check and the update, the dreaded race condition 1 2 Thre read C d Coordi rdination Formalizing ¡ “ Too ¡Much ¡Milk ” ¡ Too much milk! Shared variables Ø “ Look in the fridge for milk ” – check a variable Ø “ Put milk away ” – update a variable Jill Jack Safety property Look in the fridge; out of Ø At most one person buys milk milk Go to store Liveness Look in fridge; out of milk Buy milk Ø Someone buys milk when needed Go to store Arrive home; put milk away Buy milk How can we solve this problem? Arrive home; put milk away Oh, no! Fridge and milk are shared data structures 3 4 How ¡to ¡think ¡about ¡synchronization ¡code ¡ The ¡correctness ¡conditions ¡ Every thread has the same pattern Safety Ø Entry section: code to attempt entry to critical section Ø Only one thread in the critical region Ø Critical section: code that requires isolation (e.g., with mutual Liveness exclusion) Ø Some thread that enters the entry section eventually enters the Ø Exit section: cleanup code after execution of critical region critical region Ø Non-critical section: everything else Ø Even if some thread takes forever in non-critical region There can be multiple critical regions in a program Bounded waiting Ø Only critical regions that access the same resource (e.g., data Ø A thread that enters the entry section enters the critical section structure) need to synchronize with each other within some bounded number of operations. Failure atomicity while(1) { Ø It is OK for a thread to die in the critical region Entry section Ø Many techniques do not provide failure atomicity Critical section while(1) { Entry section Exit section Critical section Non-critical section Exit section } Non-critical section } 5 6

  2. Too ¡Much ¡Milk: ¡Solution ¡#0 ¡ Too ¡Much ¡Milk: ¡Solution ¡#1 ¡ turn := Jill // Initialization while(1) { if (noMilk) { // check milk (Entry section) while(1) { while(1) { if (noNote) { // check if roommate is getting milk while(turn ≠ Jack) ; //spin while(turn ≠ Jill) ; //spin leave Note; //Critical section while (Milk) ; //spin while (Milk) ; //spin buy milk; buy milk; // Critical section buy milk; remove Note; // Exit section turn := Jill // Exit section turn := Jack } // Non-critical section // Non-critical section // Non-critical region } } } Is this solution Is this solution Ø 1. Correct Ø 1. Correct Ø 2. Not safe Ø 2. Not safe Ø 3. Not live Ø 3. Not live Ø 4. No bounded wait Ø 4. No bounded wait Ø 5. Not safe and not live What if we switch the Ø 5. Not safe and not live order of checks? It works sometime and doesn’t some other times At least it is safe Ø Threads can be context switched between checking and leaving note Ø Live, note left will be removed Ø Bounded wait (‘buy milk’ takes a finite number of steps) 7 8 Solution ¡#2 ¡(a.k.a. ¡Peterson ’ s ¡algorithm): ¡ ¡ Peters rson ’ s A Algori rithm combine ¡ideas ¡of ¡0 ¡and ¡1 ¡ in 0 = in 1 = false; Jack Jill Variables: while (1) { while (1) { Spin! Ø in i : thread T i is executing , or attempting to execute, in CS in 0 := true; in 1 := true; Ø turn : id of thread allowed to enter CS if multiple want to turn := Jill; turn := Jack; while (turn == Jill while (turn == Jack && in 1 ) ;//wait && in 0 );//wait Claim: We can achieve mutual exclusion if the following invariant holds Critical section Critical section before thread i enters the critical section: in 0 := false; in 1 := false; Non-critical section } Non-critical section } ((¬ in 0 ∨ ( in 0 ∧ turn = 1)) ∧ in 1 ) ∧ ((¬ in 1 ∨ ( in 1 ∧ turn = 0)) ∧ in 0 ) {(¬ in j ∨ ( in j ∧ turn = i )) ∧ in i } ⇒ turn=Jill, in 0 = true turn=Jack, in 0 = false, in 1 := true turn=Jack, in 0 = true, in 1 := true (( turn = 0) ∧ ( turn = 1)) = false Safe, live, and bounded waiting But, only 2 participants Intuitively: j doesn’t want to execute or it is i’s turn to execute 9 10 Too ¡Much ¡Milk: ¡Lessons ¡ Towards ¡a ¡solution ¡ The problem boils down to establishing the following right after Peterson ’ s works, but it is really unsatisfactory entry i (¬ in j ∨ ( in j ∧ turn = i )) ∧ in i = (¬ in j ∨ turn = i ) ∧ in i Ø Limited to two threads Ø Solution is complicated; proving correctness is tricky even for the simple example Or, intuitively, right after Jack enters: Ø While thread is waiting, it is consuming CPU time u Jack has signaled that he is in the entry section ( in i ) u - And - How can we do better? u Jill isn’t in the critical section or entry section (¬ in j ) Ø Use hardware to make synchronization faster u - Or – u Jill is also in the entry section but it is Jack’s turn ( in j ∧ turn = i ) Ø Define higher-level programming abstractions to simplify concurrent programming How can we do that? entry i = in i := true; while ( in j ∧ turn ≠ i ); 11 12

  3. We h hit a a s snag What c can w we do do? ? Thread T 0 Add assignment to turn to establish the second disjunct while (!terminate) { Thread T 1 in 0 := true while (!terminate) { { in 0 } Thread T 0 Thread T 1 in 1 := true while ( in 1 ∧ turn ≠ 0); while (!terminate) { while (!terminate) { { in 1 } in 0 := true; in 1 := true; { in 0 ∧ (¬ in 1 ∨ turn = 0)} α 0 while ( in 0 ∧ turn ≠ 1); turn := 1; turn := 0; α 1 CS 0 { in 0 } { in 1 } { in 1 ∧ (¬ in 0 ∨ turn = 1)} ……… while ( in 1 ∧ turn ≠ 0); while ( in 0 ∧ turn ≠ 1); CS 1 { in 0 ∧ (¬ in 1 ∨ turn = 0 ∨ at( α 1 ) )} { in 1 ∧ (¬ in 0 ∨ turn = 1 ∨ at( α 0 ) )} ……… } CS 0 CS 1 in 0 := false; in 1 := false; } NCS 0 NCS 1 } } The assignment to in 0 invalidates the invariant! 13 14 Safe? ? Live? ? Thread T 0 Thread T 1 while (!terminate) { while (!terminate) { Thread T 0 Thread T 1 {S 1 : ¬ in 0 ∧ ( turn = 1 ∨ turn = 0)} {R 1 : ¬ in 0 ∧ ( turn = 1 ∨ turn = 0)} while (!terminate) { while (!terminate) { in 0 := true; in 1 := true; in 0 := true; in 1 := true; {S 2 : in 0 ∧ ( turn = 1 ∨ turn = 0)} {R 2 : in 0 ∧ ( turn = 1 ∨ turn = 0)} α 0 α 1 turn := 1; turn := 0; α 0 turn := 1; α 1 turn := 0; { in 0 } { in 1 } {S 2 } {R 2 } while ( in 1 ∧ turn ≠ 0); while ( in 0 ∧ turn ≠ 1); while ( in 1 ∧ turn ≠ 0); while ( in 0 ∧ turn ≠ 1); {S 3 : in 0 ∧ (¬ in 1 ∨ at( α 1 ) ∨ turn = 0)} {R 3 : in 1 ∧ (¬ in 0 ∨ at( α 0 ) ∨ turn = 1)} { in 0 ∧ (¬ in 1 ∨ turn = 0 ∨ at( α 1 ) )} { in 1 ∧ (¬ in 0 ∨ turn = 1 ∨ at( α 0 ) )} CS 0 CS 1 CS 1 CS 0 {S 3 } {R 3 } in 1 := false; in 0 := false; in 0 := false; in 1 := false; NCS 1 NCS 0 {S 1 } {R 1 } } } NCS 0 NCS 1 } } If both in CS, then Non-blocking: T 0 before NCS 0 , T 1 stuck at while loop in 0 ∧ ( ¬in 1 ∨ at( α 1 ) ∨ turn = 0) ∧ in 1 ∧ ( ¬in 0 ∨ at( α 0 ) ∨ turn = 1) ∧ S 1 ∧ R 2 ∧ in 0 ∧ ( turn = 0) = ¬in 0 ∧ in 1 ∧ in 0 ∧ ( turn = 0) = false ∧ ¬ at( α 0 ) ∧ ¬ at( α 1 ) = ( turn = 0) ∧ ( turn = 1) = false Deadlock-free: T 1 and T 0 at while , before entering the critical section S 2 ∧ R 2 ∧ ( in 0 ∧ ( turn = 0)) ∧ ( in 1 ∧ ( turn = 1)) ⇒ ( turn = 0) ∧ ( turn = 1) = false 15 16 Bounde ded w d waiting? ? Thread T 0 Thread T 1 while (!terminate) { while (!terminate) { in 0 := true; in 1 := true; turn := 1; turn := 0; while ( in 1 ∧ turn ≠ 0); while ( in 0 ∧ turn ≠ 1); CS 0 CS 0 in 0 := false; in 1 := false; NCS 0 NCS 0 } } Yup! 17

Recommend


More recommend