Presentation is loading. Please wait.

Presentation is loading. Please wait.

Implementing Mutual Exclusion Andy Wang Operating Systems COP 4610 / CGS 5765.

Similar presentations


Presentation on theme: "Implementing Mutual Exclusion Andy Wang Operating Systems COP 4610 / CGS 5765."— Presentation transcript:

1 Implementing Mutual Exclusion Andy Wang Operating Systems COP 4610 / CGS 5765

2 From the Previous Lecture  The too-much-milk example shows that writing concurrent programs with load and store instructions (i.e., C assignment statements) is tricky  Programmers want to use higher- level operations, such as locks

3 Ways of Implementing Locks Locking primitives High-level atomic operations Locks, semaphores, monitors, send/receive Low-level atomic operations Load/store, interrupt disables, test_and_set  All implementations require some level of hardware support

4 Atomic Memory Load and Store  C assignment statements  Examples: too-much-milk solutions

5 Disable Interrupts (for Uniprocessors)  On a uniprocessor, –One way to make an operation atomic is to disallow a context switch to occur in the middle of an operation  Solution 1 Lock::Acquire() { // disable interrupts; } Lock::Release() { // enable interrupts; }

6 An Example lock  Acquire(); if (no milk) { // get milk } lock  Release();

7 Problems with Solution 1  A user-level program may not re- enable interrupts –The OS can no longer regain the control  No guarantees on the duration of interrupts; bad for real-time systems  Solution 1 will not work for more complex scenarios (nested locks)

8 Solution 2 class Lock { int value = FREE; } Lock::Acquire() { // disable interrupts while (value != FREE) { // enable interrupts // disable interrupts } value = BUSY; // enable interrupts } Lock::Release() { // disable interrupts value = FREE; // enable interrupts }

9 Solution 2 class Lock { int value = FREE; } Lock::Acquire() { // disable interrupts while (value != FREE) { // enable interrupts // disable interrupts } value = BUSY; // enable interrupts } Lock::Release() { // disable interrupts value = FREE; // enable interrupts } The lock is initially FREE.

10 Solution 2 class Lock { int value = FREE; } Lock::Acquire() { // disable interrupts while (value != FREE) { // enable interrupts // disable interrupts } value = BUSY; // enable interrupts } Lock::Release() { // disable interrupts value = FREE; // enable interrupts } Check the lock value while interrupts are disabled.

11 Solution 2 class Lock { int value = FREE; } Lock::Acquire() { // disable interrupts while (value != FREE) { // enable interrupts // disable interrupts } value = BUSY; // enable interrupts } Lock::Release() { // disable interrupts value = FREE; // enable interrupts } Re-enable interrupts inside the loop, so someone may have a chance to unlock.

12 Solution 2 class Lock { int value = FREE; } Lock::Acquire() { // disable interrupts while (value != FREE) { // enable interrupts // disable interrupts } value = BUSY; // enable interrupts } Lock::Release() { // disable interrupts value = FREE; // enable interrupts } Disable the interrupts again before checking the lock.

13 Solution 2 class Lock { int value = FREE; } Lock::Acquire() { // disable interrupts while (value != FREE) { // enable interrupts // disable interrupts } value = BUSY; // enable interrupts } Lock::Release() { // disable interrupts value = FREE; // enable interrupts } If no one is holding the lock, grab the lock.

14 Problems with Solution 2  It works for a single processor  It does not work on a multi- processor machine –Other CPUs can still enter the critical section

15 The test_and_set Operation  test_and_set also works on multiprocessors –Atomically reads a memory location –Sets it to 1 –Returns the old value of memory location

16 The test_and_set Operation value = 0; Lock::Acquire() { // while the previous value is BUSY, loop while (test_and_set(value) == 1); } Lock::Release() { value = 0; }

17 Problems with Mentioned Approaches  Busy-waiting: hogging CPU cycles while a thread is waiting for a lock –Very inefficient –Can be avoided with a waiting queue

18 Locks Using Interrupt Disables, Without Busy-Waiting class Lock { int value = FREE; } Lock::Acquire() { // disable interrupts if (value != FREE) { // Queue the thread // Go to sleep } else { value = BUSY; } // enable interrupts } Lock::Release() { // disable interrupts if (someone is waiting) { // wake a thread // Put it on ready queue } else { value = FREE; } // enable interrupts }

19 Locks Using Interrupt Disables, Without Busy-Waiting class Lock { int value = FREE; } Lock::Acquire() { // disable interrupts if (value != FREE) { // Queue the thread // Go to sleep } else { value = BUSY; } // enable interrupts } Lock::Release() { // disable interrupts if (someone is waiting) { // wake a thread // Put it on ready queue } else { value = FREE; } // enable interrupts } Thread 1 tries to grab the lock. Thread 1

20 Locks Using Interrupt Disables, Without Busy-Waiting class Lock { int value = FREE; } Lock::Acquire() { // disable interrupts if (value != FREE) { // Queue the thread // Go to sleep } else { value = BUSY; } // enable interrupts } Lock::Release() { // disable interrupts if (someone is waiting) { // wake a thread // Put it on ready queue } else { value = FREE; } // enable interrupts } No more busy waiting… Thread 1

21 Locks Using Interrupt Disables, Without Busy-Waiting class Lock { int value = FREE; } Lock::Acquire() { // disable interrupts if (value != FREE) { // Queue the thread // Go to sleep } else { value = BUSY; } // enable interrupts } Lock::Release() { // disable interrupts if (someone is waiting) { // wake a thread // Put it on ready queue } else { value = FREE; } // enable interrupts } Grab the lock. Thread 1

22 Locks Using Interrupt Disables, Without Busy-Waiting class Lock { int value = FREE; } Lock::Acquire() { // disable interrupts if (value != FREE) { // Queue the thread // Go to sleep } else { value = BUSY; } // enable interrupts } Lock::Release() { // disable interrupts if (someone is waiting) { // wake a thread // Put it on ready queue } else { value = FREE; } // enable interrupts } Thread 1 goes on computing. Thread 1

23 Locks Using Interrupt Disables, Without Busy-Waiting class Lock { int value = FREE; } Lock::Acquire() { // disable interrupts if (value != FREE) { // Queue the thread // Go to sleep } else { value = BUSY; } // enable interrupts } Lock::Release() { // disable interrupts if (someone is waiting) { // wake a thread // Put it on ready queue } else { value = FREE; } // enable interrupts } Thread 2 tries to grab the lock. Thread 2

24 Locks Using Interrupt Disables, Without Busy-Waiting class Lock { int value = FREE; } Lock::Acquire() { // disable interrupts if (value != FREE) { // Queue the thread // Go to sleep } else { value = BUSY; } // enable interrupts } Lock::Release() { // disable interrupts if (someone is waiting) { // wake a thread // Put it on ready queue } else { value = FREE; } // enable interrupts } The lock is busy… Thread 2

25 Locks Using Interrupt Disables, Without Busy-Waiting class Lock { int value = FREE; } Lock::Acquire() { // disable interrupts if (value != FREE) { // Queue the thread // Go to sleep } else { value = BUSY; } // enable interrupts } Lock::Release() { // disable interrupts if (someone is waiting) { // wake a thread // Put it on ready queue } else { value = FREE; } // enable interrupts } Put the thread 2 on a waiting queue. Thread 2

26 Locks Using Interrupt Disables, Without Busy-Waiting class Lock { int value = FREE; } Lock::Acquire() { // disable interrupts if (value != FREE) { // Queue the thread // Go to sleep } else { value = BUSY; } // enable interrupts } Lock::Release() { // disable interrupts if (someone is waiting) { // wake a thread // Put it on ready queue } else { value = FREE; } // enable interrupts } Go to sleep. Wait for the princess charming…Context switch within the sleep. Thread 2

27 Locks Using Interrupt Disables, Without Busy-Waiting class Lock { int value = FREE; } Lock::Acquire() { // disable interrupts if (value != FREE) { // Queue the thread // Go to sleep } else { value = BUSY; } // enable interrupts } Lock::Release() { // disable interrupts if (someone is waiting) { // wake a thread // Put it on ready queue } else { value = FREE; } // enable interrupts } Say thread 1 wants to release the lock (interrupts are already disabled by thread 2). Thread 1

28 Locks Using Interrupt Disables, Without Busy-Waiting class Lock { int value = FREE; } Lock::Acquire() { // disable interrupts if (value != FREE) { // Queue the thread // Go to sleep } else { value = BUSY; } // enable interrupts } Lock::Release() { // disable interrupts if (someone is waiting) { // wake a thread // Put it on ready queue } else { value = FREE; } // enable interrupts } Hello? Is someone waiting there? Is someone waiting there? Thread 2 is waiting. Thread 1

29 Locks Using Interrupt Disables, Without Busy-Waiting class Lock { int value = FREE; } Lock::Acquire() { // disable interrupts if (value != FREE) { // Queue the thread // Go to sleep } else { value = BUSY; } // enable interrupts } Lock::Release() { // disable interrupts if (someone is waiting) { // wake a thread // Put it on ready queue } else { value = FREE; } // enable interrupts } Put thread 2 on ready queue; context switch. Thread 1

30 Locks Using Interrupt Disables, Without Busy-Waiting class Lock { int value = FREE; } Lock::Acquire() { // disable interrupts if (value != FREE) { // Queue the thread // Go to sleep } else { value = BUSY; } // enable interrupts } Lock::Release() { // disable interrupts if (someone is waiting) { // wake a thread // Put it on ready queue } else { value = FREE; } // enable interrupts } Thread 2: Who kissed me? I don’t do mornings… Thread 2

31 Locks Using Interrupt Disables, Without Busy-Waiting class Lock { int value = FREE; } Lock::Acquire() { // disable interrupts if (value != FREE) { // Queue the thread // Go to sleep } else { value = BUSY; } // enable interrupts } Lock::Release() { // disable interrupts if (someone is waiting) { // wake a thread // Put it on ready queue } else { value = FREE; } // enable interrupts } Thread 2 is done with its computation. Thread 2

32 Locks Using Interrupt Disables, Without Busy-Waiting class Lock { int value = FREE; } Lock::Acquire() { // disable interrupts if (value != FREE) { // Queue the thread // Go to sleep } else { value = BUSY; } // enable interrupts } Lock::Release() { // disable interrupts if (someone is waiting) { // wake a thread // Put it on ready queue } else { value = FREE; } // enable interrupts } Suppose no one else is waiting. Thread 2

33 Locks Using Interrupt Disables, Without Busy-Waiting class Lock { int value = FREE; } Lock::Acquire() { // disable interrupts if (value != FREE) { // Queue the thread // Go to sleep } else { value = BUSY; } // enable interrupts } Lock::Release() { // disable interrupts if (someone is waiting) { // wake a thread // Put it on ready queue } else { value = FREE; } // enable interrupts } Release the lock. (Thread 1 has finished its work, so it’s okay.) Thread 2

34 Locks Using Interrupt Disables, Without Busy-Waiting class Lock { int value = FREE; } Lock::Acquire() { // disable interrupts if (value != FREE) { // Queue the thread // Go to sleep } else { value = BUSY; } // enable interrupts } Lock::Release() { // disable interrupts if (someone is waiting) { // wake a thread // Put it on ready queue } else { value = FREE; } // enable interrupts } Warp 9, engage (let’s get out of here)… Thread 2

35 Locks Using Interrupt Disables, Without Busy-Waiting class Lock { int value = FREE; } Lock::Acquire() { // disable interrupts if (value != FREE) { // Queue the thread // Go to sleep } else { value = BUSY; } // enable interrupts } Lock::Release() { // disable interrupts if (someone is waiting) { // wake a thread // Put it on ready queue } else { value = FREE; } // enable interrupts } Eventually, the kernel will context switch back to thread 1…Thread 1: What happened? Thread 1

36 So, What’s Going On?  Interrupt disable and enable operations occur across context switches (at the steady state)

37 So, What’s Going On? Thread A Thread B Disable interrupts Sleep Disable interrupts Sleep Return from sleep Enable interrupts Context switch Return from sleep Enable interrupts Context switch

38 Locks Using Interrupt Disables, Without Busy-Waiting class Lock { int value = FREE; } Lock::Acquire() { // disable interrupts if (value != FREE) { // Queue the thread // Go to sleep } else { value = BUSY; } // enable interrupts } Lock::Release() { // disable interrupts if (someone is waiting) { // wake a thread // Put it on ready queue } else { value = FREE; } // enable interrupts } CPU scheduler FIFO queue Thread 1 Thread 2 Thread 3

39 Locks Using Interrupt Disables, Without Busy-Waiting class Lock { int value = FREE; } Lock::Acquire() { // disable interrupts if (value != FREE) { // Queue the thread // Go to sleep } else { value = BUSY; } // enable interrupts } Lock::Release() { // disable interrupts if (someone is waiting) { // wake a thread // Put it on ready queue } else { value = FREE; } // enable interrupts } CPU scheduler FIFO queue Thread 1 Thread 2 Thread 3

40 Locks Using Interrupt Disables, Without Busy-Waiting class Lock { int value = FREE; } Lock::Acquire() { // disable interrupts if (value != FREE) { // Queue the thread // Go to sleep } else { value = BUSY; } // enable interrupts } Lock::Release() { // disable interrupts if (someone is waiting) { // wake a thread // Put it on ready queue } else { value = FREE; } // enable interrupts } CPU scheduler FIFO queue Thread 2 Thread 3 Thread 1

41 Locks Using Interrupt Disables, Without Busy-Waiting class Lock { int value = FREE; } Lock::Acquire() { // disable interrupts if (value != FREE) { // Queue the thread // Go to sleep } else { value = BUSY; } // enable interrupts } Lock::Release() { // disable interrupts if (someone is waiting) { // wake a thread // Put it on ready queue } else { value = FREE; } // enable interrupts } CPU scheduler FIFO queue Thread 2 Thread 3 Thread 1

42 Locks Using Interrupt Disables, Without Busy-Waiting class Lock { int value = FREE; } Lock::Acquire() { // disable interrupts if (value != FREE) { // Queue the thread // Go to sleep } else { value = BUSY; } // enable interrupts } Lock::Release() { // disable interrupts if (someone is waiting) { // wake a thread // Put it on ready queue } else { value = FREE; } // enable interrupts } CPU scheduler FIFO queue Thread 2 Thread 3 Thread 1

43 Locks Using Interrupt Disables, Without Busy-Waiting class Lock { int value = FREE; } Lock::Acquire() { // disable interrupts if (value != FREE) { // Queue the thread // Go to sleep } else { value = BUSY; } // enable interrupts } Lock::Release() { // disable interrupts if (someone is waiting) { // wake a thread // Put it on ready queue } else { value = FREE; } // enable interrupts } CPU scheduler FIFO queue Thread 2 Thread 3 Thread 1

44 Locks Using Interrupt Disables, Without Busy-Waiting class Lock { int value = FREE; } Lock::Acquire() { // disable interrupts if (value != FREE) { // Queue the thread // Go to sleep } else { value = BUSY; } // enable interrupts } Lock::Release() { // disable interrupts if (someone is waiting) { // wake a thread // Put it on ready queue } else { value = FREE; } // enable interrupts } CPU scheduler FIFO queue Thread 2 Thread 3 Thread 1

45 Locks Using Interrupt Disables, Without Busy-Waiting class Lock { int value = FREE; } Lock::Acquire() { // disable interrupts if (value != FREE) { // Queue the thread // Go to sleep } else { value = BUSY; } // enable interrupts } Lock::Release() { // disable interrupts if (someone is waiting) { // wake a thread // Put it on ready queue } else { value = FREE; } // enable interrupts } CPU scheduler FIFO queue Thread 2 Thread 3 Thread 1

46 Locks Using Interrupt Disables, Without Busy-Waiting class Lock { int value = FREE; } Lock::Acquire() { // disable interrupts if (value != FREE) { // Queue the thread // Go to sleep } else { value = BUSY; } // enable interrupts } Lock::Release() { // disable interrupts if (someone is waiting) { // wake a thread // Put it on ready queue } else { value = FREE; } // enable interrupts } CPU scheduler FIFO queue Thread 3 Thread 2 Thread 1

47 Locks Using Interrupt Disables, Without Busy-Waiting class Lock { int value = FREE; } Lock::Acquire() { // disable interrupts if (value != FREE) { // Queue the thread // Go to sleep } else { value = BUSY; } // enable interrupts } Lock::Release() { // disable interrupts if (someone is waiting) { // wake a thread // Put it on ready queue } else { value = FREE; } // enable interrupts } CPU scheduler FIFO queue Thread 3 Thread 2 Thread 1

48 Locks Using Interrupt Disables, Without Busy-Waiting class Lock { int value = FREE; } Lock::Acquire() { // disable interrupts if (value != FREE) { // Queue the thread // Go to sleep } else { value = BUSY; } // enable interrupts } Lock::Release() { // disable interrupts if (someone is waiting) { // wake a thread // Put it on ready queue } else { value = FREE; } // enable interrupts } CPU scheduler FIFO queue Thread 1 Thread 3 Thread 2

49 Locks Using Interrupt Disables, Without Busy-Waiting class Lock { int value = FREE; } Lock::Acquire() { // disable interrupts if (value != FREE) { // Queue the thread // Go to sleep } else { value = BUSY; } // enable interrupts } Lock::Release() { // disable interrupts if (someone is waiting) { // wake a thread // Put it on ready queue } else { value = FREE; } // enable interrupts } CPU scheduler FIFO queue Thread 1 Thread 2 Thread 3

50 Locks Using Interrupt Disables, Without Busy-Waiting class Lock { int value = FREE; } Lock::Acquire() { // disable interrupts if (value != FREE) { // Queue the thread // Go to sleep } else { value = BUSY; } // enable interrupts } Lock::Release() { // disable interrupts if (someone is waiting) { // wake a thread // Put it on ready queue } else { value = FREE; } // enable interrupts } CPU scheduler FIFO queue Thread 1 Thread 3 Thread 2

51 Locks Using Interrupt Disables, Without Busy-Waiting class Lock { int value = FREE; } Lock::Acquire() { // disable interrupts if (value != FREE) { // Queue the thread // Go to sleep } else { value = BUSY; } // enable interrupts } Lock::Release() { // disable interrupts if (someone is waiting) { // wake a thread // Put it on ready queue } else { value = FREE; } // enable interrupts } CPU scheduler FIFO queue Thread 1 Thread 3 Thread 2

52 Locks Using Interrupt Disables, Without Busy-Waiting class Lock { int value = FREE; } Lock::Acquire() { // disable interrupts if (value != FREE) { // Queue the thread // Go to sleep } else { value = BUSY; } // enable interrupts } Lock::Release() { // disable interrupts if (someone is waiting) { // wake a thread // Put it on ready queue } else { value = FREE; } // enable interrupts } CPU scheduler FIFO queue Thread 2 Thread 3

53 Locks Using Interrupt Disables, Without Busy-Waiting class Lock { int value = FREE; } Lock::Acquire() { // disable interrupts if (value != FREE) { // Queue the thread // Go to sleep } else { value = BUSY; } // enable interrupts } Lock::Release() { // disable interrupts if (someone is waiting) { // wake a thread // Put it on ready queue } else { value = FREE; } // enable interrupts } CPU scheduler FIFO queue Thread 2

54 Locks Using test_and_set, With Minimal Busy-Waiting  Impossible to use test_and_set to avoid busy-waiting  However, waiting can be minimized –with a waiting queue

55 Locks Using test_and_set, With Minimal Busy-Waiting class Lock { int value = FREE; int guard = 0; int guard = 0;} Lock::Acquire() { while (test_and_set(guard)); if (value != FREE) { // queue the thread // guard = 0 and sleep } else { value = BUSY; } guard = 0; } Lock::Release() { while (test_and_set(guard)); if (anyone waiting) { // wake up one thread // put it on ready queue } else { value = FREE; } guard = 0; }


Download ppt "Implementing Mutual Exclusion Andy Wang Operating Systems COP 4610 / CGS 5765."

Similar presentations


Ads by Google