




Study with the several resources on Docsity
Earn points by helping other students or get them with a premium plan
Prepare for your exams
Study with the several resources on Docsity
Earn points to download
Earn points by helping other students or get them with a premium plan
The problem of concurrency in multithreaded programming and the need for mutual exclusion to prevent race conditions. It discusses various methods for achieving mutual exclusion, including shared lock variables, strict alternation, check then lock, and peterson's algorithm. The document also covers the importance of progress and the need for atomic operations.
Typology: Study notes
1 / 8
This page cannot be seen from the preview
Don't miss anything!





Maria Hybinette, UGA
» What are race conditions? » What are critical sections? » What are atomic operations?
» Initialization: balance = 100 » Maria: deposit( 200 ) » Tucker: deposit( 10 )
Which variables are shared? Which private?
1. Initialization: balance = 100 2. Maria: deposit( 200 ) 3. Tucker: deposit( 10 )
» Observation: When a thread is interrupted content of registers are saved (and restored) by interrupt handlers.
! Local variables are not shared (private)
! Global variables and static objects are shared
! Dynamic objects and other heap objects are shared
» Result in non-deterministic bugs, hard to fine!
» What about if no one gets into the critical section even if several threads wants to get in? » What about if someone waits outside the critical section and never gets a turn?
Process Maria Process Tucker Time Maria enters her critical section Maria leaves her critical section Tucker attempts to enter his critical section Tucker is blocked, and waits Tucker enters his critical section void { deposit( int amount ) Tucker leaves his critical section balance = balance + amount; }
» Only one thread in critical section at a time
» Not block others out: if there are requests to enter the CS must allow one to proceed (e.g., no deadlocks). » Must not depend on threads outside critical section
» Must eventually allow each waiting thread to enter
Bounded Waiting No Starvation Shared Lock Variable X Progress someone gets the CS Mutual Exclusion ! Problems:
! Lessons: Failed because two threads read the lock variable simultaneously and both thought it was their ‘turn’ to get into the critical section
» Mutual exclusion?
» Bounded Waiting (no starvation)? int turn = 0; // shared variable void deposit( int amount ) { while( turn <> 1-tid ) {} /* wait */ ; balance += amount; // critical section turn = 1-tid; } Entry CS: CS: Exit CS:
int turn = 0; // shared variable void deposit( int amount ) { while( turn <> 1-tid ) {} /* wait */ ; balance += amount; // critical section turn = 1-tid; }
0: Process Maria 1: Process Tucker Time Tucker is not interested in CS Maria is blocking!
! Problems:
Strict Alteration Yes No No Bounded Waiting No Starvation Shared Lock Variable No Progress someone gets the CS Mutual Exclusion Pace limited to slowest process
» Pragmatically: Problem with the turn variable is that we need state information about BOTH processes.
» We need to know the needs of others! » Check to see if other needs it. Don’t get the lock until the ‘other’ is done with it.
! Does this work? Mutual exclusion? Progress (someone gets the CS if empty, no deadlock)? Bounded Waiting (no starvation)? boolean lock[2] = {false, false} // shared void deposit( int amount ) { while( lock[1-tid] == true ) {} /* wait */ ; lock[tid] = true; balance += amount; // critical section lock[tid] = false; } Entry CS: CS: Exit CS:
boolean void deposit( lock[2] int = {false,amount )false} // shared { while( lock[1-tid] == true ) {} /* wait */; lock[tid] = true; balance += amount; // critical section lock[tid] } = false;
! M checks if Tucker is interested and he isn’t ! T checks if Maria is interested and she isn’t ! Switch lock back to Maria she now sets his ! Switch Back to Tucker he sets his lock 0: Process Maria 1: Process Tucker Time Enter CS Enter CS
! Problems:
! Lesson: Process lock’s the critical section AFTER the process has checked it is available but before it enters the section. ! Idea: Lock the section first! then lock Check then Lock No Strict Alteration Yes No No Bounded Waiting No Starvation Shared Lock Variable No Progress someone gets the CS Mutual Exclusion Pace limited to slowest process
! Does this work? Mutual exclusion? Progress (someone gets the CS if empty, no deadlock)? Bounded Waiting (no starvation)? boolean lock[2] = {false, false} // shared void deposit( int amount ) { lock[tid] = true; while( lock[1-tid] == true ) {} /* wait */ ; balance += amount; // critical section lock[tid] = false; } Entry CS: CS: Exit CS:
boolean lock[2] = {false, false} // shared void { deposit( int amount ) lock[tid] = true; while( lock[1-tid] == true ) {} /* wait */; balance += amount; // critical section lock[tid] } = false;
» Tucker cannot enter until Maria is done » Tucker blocks alreadyuntil Tucker in CS, leaves then theMaria CS
Time 0: Process Maria 1: Process Tucker boolean lock[2] = {false, false} // shared void { deposit( int amount ) lock[tid] = true; while( lock[1-tid] == true ) {} /* wait */; balance += amount; // critical section lock[tid] } = false;
Time 0: Process Maria 1: Process Tucker Maria waits for Tucker Tucker waits for Maria
Lock then Check Yes No (deadlock) Check then Lock No Strict Alteration Yes No No Bounded Waiting No Starvation Shared Lock Variable No Progress someone gets the CS Mutual Exclusion Pace limited to slowest process
boolean lock[2] = {false, false} // shared int turn = 0; // shared variable void deposit( int amount ) { lock[tid] = true; while( lock[1-tid] == true ) // check other { if( turn == 1-tid ) // other turn to insist lock[tid] = false; // then I defer while( turn == 1 - tid ) {}; lock[tid] = true; } balance += amount; // critical section turn = 1 - tid; lock[tid] = false; }
! Idea: also combines turn and separate locks ! When 2 processes enters simultaneously, setting turn to the other releases the ‘other’ process from the while loop (one write will be last). ! Mutual Exclusion: Key Observation: turn cannot be both 0 and 1 at the same time boolean lock[2] = {false, false} // shared int turn = 0; // shared variable void deposit( int amount ) { lock[tid] = true; turn = 1-tid; while( lock[1-tid] == true && turn == 1-tid ) {}; balance += amount; // critical section lock[tid] = false; }
boolean int turn lock[2] = 0; // = shared{false, variable false} // shared void { deposit( int amount ) lock[tid] = true; turn while( = 1-tid;lock[1-tid] == true && turn == 1-tid ) {}; balance lock[tid] += = amount;false; // critical section }
Peterson Yes Yes Yes Dekker Yes Yes Yes Deferral Yes (not deadlock)^ No Not really Lock then Check Yes No (deadlock) Check then Lock No Strict Alteration Yes No No Bounded Waiting No Starvation Shared Lock Variable No Progress someone gets the CS Mutual Exclusion Pace limited to slowest process Simpler
! Idea: Bakery -- each thread picks next highest ticket (may have ties) ! Enter critical section when have lowest ticket ! Data Structures (size N):
! Ticket is a pair: ( number[tid], i ) ! Lexicographical order:
! Pick next highest ticket (may have ties) ! Enter CS when my ticket is the lowest
choosing[tid] = true; number[tid] = max( number[0], … , number[n-1] ) + 1; choosing[tid] = false; for(j = 0; j < n; j++) while( choosing[j] ){}; // wait until j is done choosing // wait until number[j] = 0 (not interested) or me smallest number while( number[j]!= 0 && ( (number[j],j) < (number[tid],tid)) ); balance += amount; number[tid] = 0;