MODERN MULTITHREADING Implementing Testing and Debugging Multithreaded Java
MODERN MULTITHREADING Implementing, Testing, and Debugging Multithreaded Java and C++/Pthreads/Win 32 Programs Chapter 2. THE CRITICAL SECTION PROBLEM 29 -Mar-08 GNU OS Lab. Ok Gyoon Ha
[Modern Threading] Contents 2. 1 Software Solutions to The Two-Thread Critical Section Problem 2. 2 Ticket-Based Solutions to The n-Thread Critical Section Problem 2. 3 Hardware Solutions to The n-Thread Critical Section Problem 2. 4 Dead. Lock, Live. Lock, and Starvation 2. 5 Tracing and Replay for Shared Variables 2008 -03 -29
[Modern Threading] Background ▲ Critical Section while (true) { entry-section critical section exit-section noncritical section } entry exit noncritical ▲ Three correctness requirements - Mutual exclusion: guarantee only one thread executes in its critical section - Progress: decide which thread will enter its critical section next - Bounded waiting: bound the waiting time until thread’s request is granted 2008 -03 -29 3
[Modern Threading] Software Solutions to The Two-Thread Critical Section Problem ▲ Incorrect Solution 1 T 0 T 1 while (true) { while (intend. To. Enter 1) {; } intend. To. Enter 0 = true; critical section intend. To. Enter 0 = false noncritical section } (1) (2) (3) (4) (5) while (true) { while (intend. To. Enter 0) {; } intend. To. Enter 1 = true; critical section intend. To. Enter 1 = false noncritical section } (1) (2) (3) (4) (5) (1) (2) (3) does not guarantee mutual exclusion (2) (3) 2008 -03 -29 4
[Modern Threading] Software Solutions to The Two-Thread Critical Section Problem ▲ Incorrect Solution 2 int turn =1 ; T 0 T 1 while (true) { while (turn != 0) {; } critical section turn 1; noncritical section } Repeats forever 2008 -03 -29 (1) (2) (3) (4) (1) while (true) { while (turn != 1) {; } critical section turn 0; noncritical section } (1) (2) (3) (4) the progress requirement is violated 5
[Modern Threading] Software Solutions to The Two-Thread Critical Section Problem ▲ Incorrect Solution 3 (1/2) T 0 while (true) { intend. To. Enter 0 = true; while (intend. To. Enter 1) { intend. To. Enter 0 = false; while(intend. To. Enter 1){; } intend. To. Enter 0 = true; } critical section intend. To. Enter 0 = false noncritical section } T 1 (1) (2) (3) (4) (5) (6) (7) (8) while (true) { intend. To. Enter 1 = true; while (intend. To. Enter 0) { intend. To. Enter 1 = false; while(intend. To. Enter 0){; } intend. To. Enter 1 = true; } critical section intend. To. Enter 1 = false noncritical section } (1) (2) (3) (4) (5) (6) (7) (8) - When one thread finds that the other thread intends to enter its critical section, it sets its own intend. To. Enter flag to false and waits until the other thread exits 2008 -03 -29 6
[Modern Threading] Software Solutions to The Two-Thread Critical Section Problem ▲ Incorrect Solution 3 (2/2) (1) (2) (6) (1) (2)-(3) (4) (7) (8) (1) (2) repeat infinitely does not guarantee bounded waiting (6) (4) (7) … 2008 -03 -29 7
[Modern Threading] Software Solutions to The Two-Thread Critical Section Problem ▲ Peterson’s Algorithm boolean intend. To. Enter 0 = false, intend. To. Enter 1 = false; int turn; //no initial value for turn is needed T 0 while (true) { intend. To. Enter 0 = true; turn = 1; while (intend. To. Enter 1 && turn ==1) {; } critical section intend. To. Enter 0 = false; noncritical sectioin } T 1 (1) (2) (3) (4) (5) (6) while (true) { intend. To. Enter 1 = true; turn = 0; while (intend. To. Enter 0 && turn ==0) {; } critical section intend. To. Enter 1 = false; noncritical sectioin } (1) (2) (3) (4) (5) (6) - a combination of incorrect solution 2 and 3 (correct solution) - When both threads want to enter their critical sections, referring to the way in which variable turn is used 2008 -03 -29 8
[Modern Threading] Software Solutions to The Two-Thread Critical Section Problem ▲ Using the ‘volatile’ Modifier - Peterson’s algorithm not work in the presence of certain compiler and hardware optimization (unsafe for multithreaded programs) - the compiler may allow each thread to keep private copies of shared variables (obvious problem in Peterson’s algorithm) - the solution of this potential problem is to declare shared variables as ‘volatile’ (In Java and C++) - some hardware optimizations may cause Peterson’s algorithm to fail in C++ - the solution of this problem is to add special memory instructions, called memory barriers, that constrain the optimization 2008 -03 -29 9
[Modern Threading] Ticket-Based Solution to The n-Thread Critical Section Problem ▲ Ticket Algorithm - uses variables next and permit and a special atomic operation - a thread can enter to the critical section when it has a ticket number equal to the value of variable permit (a ticket = the value of next) • next: next ticket number to be issued to a thread • permit: ticket number permitted to enter critical section • special atomic operation long Interlocked. Exchange. Add(long* target, long increament) number[i] = Interlocked. Exchange. Add(&next, 1); equivalent to number[i] = next; // these statements are executed next = next + 1; // as a critical section 2008 -03 -29 10
[Modern Threading] Ticket-Based Solution to The n-Thread Critical Section Problem ▲ Ticket Algorithm (2/2) volatile long next = 1; // next ticket number to be issued to a thread volatile long permit = 1; // ticket number permitted to enter critical section while (true) { number[i] = Interlocked. Exchange. Add(&next, 1); while (number[i] != permit {; } critical section ++permit; noncritical section } - requires special machine instructions to atomic function - the value of permit and next grow without bounds 2008 -03 -29 11
[Modern Threading] Ticket-Based Solution to The n-Thread Critical Section Problem ▲ Bakery Algorithm - uses a ticket with a pair of values (number[i], i) - a special comparision is used to order the tickets since each ticket contains a pair of values • number[i]: the ticket number • i: the ID of the thread • Ticket(a, b) < Ticket(c, d) if a < c or (a == c and b < d) - If some other thread Tj intends to enter its critical section and it has a ticket with a value that is less than Ti’s ticket, Ti waits until Tj exits critical section - satisfies the mutual exclusion, progress, and bounded waiting requirements 2008 -03 -29 12
[Modern Threading] Hardware Solution to The n-Thread Critical Section Problem ▲ Partial Solution - uses Interlocked. Exchange to guarantee mutual exclusion and progress - not guarantee bounded waiting volatile long lock = 0; while (true) { while(Interlock. Exchange(const_cast<long *>(&lock), 1) == 1) {; } critical section lock = 0; noncritical section } - When a thread exits critical section, it sets lock to 0 - an unlucky thread could be waited forever from entering its critical section 2008 -03 -29 13
[Modern Threading] Hardware Solution to The n-Thread Critical Section Problem ▲ Complete Solution - satisfies all three correctness requirements by using the global array waiting to indicate that a thread is waiting to enter its critical section 2008 -03 -29 volatile bool waiting[n]; // initialized to false volatile long lock, key; // initialized to 0 while (true) { waiting[i] = true; key = 1; while (waiting[i] && key) { key = Interlocked. Exchange(const_cast<long*>(&lock), 1); } waiting = false; critical section j = (i+1) % n; while ((j != 1) && !waiting[j]) { j= (j+1) % n; } if (j == i) lock = 0; else waiting[j] = false; noncritical section } 14
[Modern Threading] Hardware Solution to The n-Thread Critical Section Problem ▲ Note on Busy-Waiting - Busy-waiting wastes CPU cycles - to reduce the amount of busy-waiting, some type of sleep instruction can be used while (waiting[i] && key) { another thread can be guaranteed execution time Sleep(100); //release the CPU key = Interlock. Exchange(const_cast<long*>(&lock), 1); } - the value of lock can bounce repeatedly from one cache to the other - can use a simpler loop that waits for lock to became 0 it can spins locally in its cache while (waiting[i] && key) { while (lock) {; } // wait for lock to be released // try to grab lock key = Interlock. Exchange(const_cast<long*>(&lock), 1); } 2008 -03 -29 15
- Slides: 15