Implementing Mutual Exclusion

Post on 23-Jan-2016

33 views 0 download

description

Implementing Mutual Exclusion. Sarah Diesburg Operating Systems COP 4610. From the Previous Lecture. The “too much milk” example shows that writing concurrent programs directly with load and store instructions (i.e., C assignment statements) is tricky - PowerPoint PPT Presentation

Transcript of Implementing Mutual Exclusion

Implementing Mutual Implementing Mutual ExclusionExclusionSarah DiesburgSarah Diesburg

Operating SystemsOperating Systems

COP 4610COP 4610

From the Previous LectureFrom the Previous Lecture

The “too much milk” example shows The “too much milk” example shows that writing concurrent programs that writing concurrent programs directly with load and store directly with load and store instructions (i.e., C assignment instructions (i.e., C assignment statements) is trickystatements) is tricky

Programmers want to use higher-Programmers want to use higher-level operations, such as lockslevel operations, such as locks

Ways of Implementing LocksWays of Implementing Locks

Locking primitives

High-level atomic operations

Locks, semaphores, Locks, semaphores, monitors, send and monitors, send and receivereceive

Low-level atomic operations

Load/store, interrupt Load/store, interrupt disables, disables, test_and_settest_and_set

All implementations require some All implementations require some level of hardware supportlevel of hardware support

Atomic Memory Load and StoreAtomic Memory Load and Store

C assignment statementsC assignment statements Examples: “too much milk” solutionsExamples: “too much milk” solutions

Disable Interrupts (for Disable Interrupts (for Uniprocessors)Uniprocessors)

On a uniprocessor,On a uniprocessor,– An operation is atomic as long as a An operation is atomic as long as a

context switch does not occur in the context switch does not occur in the middle of an operationmiddle of an operation

Solution 1Solution 1Lock::Acquire() {Lock::Acquire() {

// disable interrupts;// disable interrupts;}}Lock::Release() {Lock::Release() {

// enable interrupts;// enable interrupts; }}

Problems with Solution 1Problems with Solution 1

A user-level program may not re-A user-level program may not re-enable interruptsenable interrupts– The kernel can no longer regain the The kernel can no longer regain the

controlcontrol No guarantees on the duration of No guarantees on the duration of

interrupts; bad for real-time systemsinterrupts; bad for real-time systems Solution 1 will not work for more Solution 1 will not work for more

complex scenarios (nested locks)complex scenarios (nested locks)

Solution 2Solution 2class Lock {class Lock {

int value = FREE;int value = FREE;}}

Lock::Acquire() {Lock::Acquire() {// disable interrupts// disable interruptswhile (value != FREE) {while (value != FREE) {

// enable interrupts// enable interrupts// disable interrupts// disable interrupts

}}value = BUSY;value = BUSY;// enable interrupts// enable interrupts

}}

Lock::Release() {Lock::Release() {

// disable interrupts// disable interrupts

value = FREE;value = FREE;

// enable interrupts// enable interrupts

}}

Solution 2Solution 2class Lock {class Lock {

int value = FREE;int value = FREE;}}

Lock::Acquire() {Lock::Acquire() {// disable interrupts// disable interruptswhile (value != FREE) {while (value != FREE) {

// enable interrupts// enable interrupts// disable interrupts// disable interrupts

}}value = BUSY;value = BUSY;// enable interrupts// enable interrupts

}}

Lock::Release() {Lock::Release() {

// disable interrupts// disable interrupts

value = FREE;value = FREE;

// enable interrupts// enable interrupts

}}

The lock is initially FREE.

Solution 2Solution 2class Lock {class Lock {

int value = FREE;int value = FREE;}}

Lock::Acquire() {Lock::Acquire() {// disable interrupts// disable interruptswhile (while (value != FREEvalue != FREE) {) {

// enable interrupts// enable interrupts// disable interrupts// disable interrupts

}}value = BUSY;value = BUSY;// enable interrupts// enable interrupts

}}

Lock::Release() {Lock::Release() {

// disable interrupts// disable interrupts

value = FREE;value = FREE;

// enable interrupts// enable interrupts

}}

Check the lock value whileinterrupts are disabled.

Solution 2Solution 2class Lock {class Lock {

int value = FREE;int value = FREE;}}

Lock::Acquire() {Lock::Acquire() {// disable interrupts// disable interruptswhile (value != FREE) {while (value != FREE) {

// enable interrupts// enable interrupts// disable interrupts// disable interrupts

}}value = BUSY;value = BUSY;// enable interrupts// enable interrupts

}}

Lock::Release() {Lock::Release() {

// disable interrupts// disable interrupts

value = FREE;value = FREE;

// enable interrupts// enable interrupts

}}

Re-enable interrupts inside theloop, so someone may have a chance to unlock.

Solution 2Solution 2class Lock {class Lock {

int value = FREE;int value = FREE;}}

Lock::Acquire() {Lock::Acquire() {// disable interrupts// disable interruptswhile (value != FREE) {while (value != FREE) {

// enable interrupts// enable interrupts// disable interrupts// disable interrupts

}}value = BUSY;value = BUSY;// enable interrupts// enable interrupts

}}

Lock::Release() {Lock::Release() {

// disable interrupts// disable interrupts

value = FREE;value = FREE;

// enable interrupts// enable interrupts

}}

Disable the interrupts againbefore checking the lock.

Solution 2Solution 2class Lock {class Lock {

int value = FREE;int value = FREE;}}

Lock::Acquire() {Lock::Acquire() {// disable interrupts// disable interruptswhile (value != FREE) {while (value != FREE) {

// enable interrupts// enable interrupts// disable interrupts// disable interrupts

}}value = BUSY;value = BUSY;// enable interrupts// enable interrupts

}}

Lock::Release() {Lock::Release() {

// disable interrupts// disable interrupts

value = FREE;value = FREE;

// enable interrupts// enable interrupts

}}

If no one is holding the lock, grab the lock.

Problems with Solution 2Problems with Solution 2

It works for a single processorIt works for a single processor It does not work on a multi-processor It does not work on a multi-processor

machinemachine– Other CPUs can still enter the critical Other CPUs can still enter the critical

sectionsection

The The test_and_settest_and_set Operation Operation

test_and_settest_and_set works on works on multiprocessorsmultiprocessors– Atomically reads a memory locationAtomically reads a memory location– Sets it to 1Sets it to 1– Returns the old value of memory Returns the old value of memory

locationlocation

The The test_and_settest_and_set Operation Operation

value = 0;value = 0;

Lock::Acquire() {Lock::Acquire() {// while the previous value is BUSY, loop// while the previous value is BUSY, loopwhile (test_and_set(value) == 1);while (test_and_set(value) == 1);

}}

Lock::Release() {Lock::Release() {value = 0;value = 0;

}}

Common Problems with Mentioned Common Problems with Mentioned ApproachesApproaches

Busy-waitingBusy-waiting: consumption of CPU : consumption of CPU cycles while a thread is waiting for a cycles while a thread is waiting for a locklock– Very inefficientVery inefficient– Can be avoided with a waiting queueCan be avoided with a waiting queue

May as well sleep instead of busy-wait…

A tail of two threads…A tail of two threads…

Suppose both threads want the lock, Suppose both threads want the lock, but like to be lazy…but like to be lazy…

Thread 1: Lazy Thread 2: Lazier

Locks Using Interrupt Disables, Locks Using Interrupt Disables, Without Busy-WaitingWithout Busy-Waiting

class Lock {class Lock {int value = FREE;int value = FREE;

}}

Lock::Acquire() {Lock::Acquire() {// disable interrupts// disable interruptsif (value != FREE) {if (value != FREE) {

// Queue the thread// Queue the thread// Go to sleep// Go to sleep

} else {} else {value = BUSY;value = BUSY;

}}// enable interrupts// enable interrupts

}}

Lock::Release() {Lock::Release() {

// disable interrupts// disable interrupts

if (someone is waiting) {if (someone is waiting) {

// wake a thread// wake a thread

// Put it on ready // Put it on ready queuequeue

} else {} else {

value = FREE;value = FREE;

}}

// enable interrupts// enable interrupts

}}

Locks Using Interrupt Disables, Locks Using Interrupt Disables, Without Busy-WaitingWithout Busy-Waiting

class Lock {class Lock {int value = FREE;int value = FREE;

}}

Lock::Acquire() {Lock::Acquire() {// disable interrupts// disable interruptsifif (value != FREE) { (value != FREE) {

// Queue the thread// Queue the thread// Go to sleep// Go to sleep

} else {} else {value = BUSY;value = BUSY;

}}// enable interrupts// enable interrupts

}}

Lock::Release() {Lock::Release() {

// disable interrupts// disable interrupts

if (someone is waiting) {if (someone is waiting) {

// wake a thread// wake a thread

// Put it on ready // Put it on ready queuequeue

} else {} else {

value = FREE;value = FREE;

}}

// enable interrupts// enable interrupts

}}

Thread 1 tries to grab the lock.

Locks Using Interrupt Disables, Locks Using Interrupt Disables, Without Busy-WaitingWithout Busy-Waiting

class Lock {class Lock {int value = FREE;int value = FREE;

}}

Lock::Acquire() {Lock::Acquire() {// disable interrupts// disable interruptsifif (value != FREE) { (value != FREE) {

// Queue the thread// Queue the thread// Go to sleep// Go to sleep

} else {} else {value = BUSY;value = BUSY;

}}// enable interrupts// enable interrupts

}}

Lock::Release() {Lock::Release() {

// disable interrupts// disable interrupts

if (someone is waiting) {if (someone is waiting) {

// wake a thread// wake a thread

// Put it on ready // Put it on ready queuequeue

} else {} else {

value = FREE;value = FREE;

}}

// enable interrupts// enable interrupts

}}

No more busy waiting…

Locks Using Interrupt Disables, Locks Using Interrupt Disables, Without Busy-WaitingWithout Busy-Waiting

class Lock {class Lock {int value = FREE;int value = FREE;

}}

Lock::Acquire() {Lock::Acquire() {// disable interrupts// disable interruptsifif (value != FREE) { (value != FREE) {

// Queue the thread// Queue the thread// Go to sleep// Go to sleep

} else {} else {value = BUSY;value = BUSY;

}}// enable interrupts// enable interrupts

}}

Lock::Release() {Lock::Release() {

// disable interrupts// disable interrupts

if (someone is waiting) {if (someone is waiting) {

// wake a thread// wake a thread

// Put it on ready // Put it on ready queuequeue

} else {} else {

value = FREE;value = FREE;

}}

// enable interrupts// enable interrupts

}}

Grab the lock.

Locks Using Interrupt Disables, Locks Using Interrupt Disables, Without Busy-WaitingWithout Busy-Waiting

class Lock {class Lock {int value = FREE;int value = FREE;

}}

Lock::Acquire() {Lock::Acquire() {// disable interrupts// disable interruptsifif (value != FREE) { (value != FREE) {

// Queue the thread// Queue the thread// Go to sleep// Go to sleep

} else {} else {value = BUSY;value = BUSY;

}}// enable interrupts// enable interrupts

}}

Lock::Release() {Lock::Release() {

// disable interrupts// disable interrupts

if (someone is waiting) {if (someone is waiting) {

// wake a thread// wake a thread

// Put it on ready // Put it on ready queuequeue

} else {} else {

value = FREE;value = FREE;

}}

// enable interrupts// enable interrupts

}}

Thread 1 goes on computing.

Locks Using Interrupt Disables, Locks Using Interrupt Disables, Without Busy-WaitingWithout Busy-Waiting

class Lock {class Lock {int value = FREE;int value = FREE;

}}

Lock::Acquire() {Lock::Acquire() {// disable interrupts// disable interruptsifif (value != FREE) { (value != FREE) {

// Queue the thread// Queue the thread// Go to sleep// Go to sleep

} else {} else {value = BUSY;value = BUSY;

}}// enable interrupts// enable interrupts

}}

Lock::Release() {Lock::Release() {

// disable interrupts// disable interrupts

if (someone is waiting) {if (someone is waiting) {

// wake a thread// wake a thread

// Put it on ready // Put it on ready queuequeue

} else {} else {

value = FREE;value = FREE;

}}

// enable interrupts// enable interrupts

}}

Thread 2 tries to grab the lock.

Locks Using Interrupt Disables, Locks Using Interrupt Disables, Without Busy-WaitingWithout Busy-Waiting

class Lock {class Lock {int value = FREE;int value = FREE;

}}

Lock::Acquire() {Lock::Acquire() {// disable interrupts// disable interruptsifif (value != FREE) {(value != FREE) {

// Queue the thread// Queue the thread// Go to sleep// Go to sleep

} else {} else {value = BUSY;value = BUSY;

}}// enable interrupts// enable interrupts

}}

Lock::Release() {Lock::Release() {

// disable interrupts// disable interrupts

if (someone is waiting) {if (someone is waiting) {

// wake a thread// wake a thread

// Put it on ready // Put it on ready queuequeue

} else {} else {

value = FREE;value = FREE;

}}

// enable interrupts// enable interrupts

}}

The lock is busy…

Locks Using Interrupt Disables, Locks Using Interrupt Disables, Without Busy-WaitingWithout Busy-Waiting

class Lock {class Lock {int value = FREE;int value = FREE;

}}

Lock::Acquire() {Lock::Acquire() {// disable interrupts// disable interruptsifif (value != FREE) { (value != FREE) {

// Queue the thread// Queue the thread// Go to sleep// Go to sleep

} else {} else {value = BUSY;value = BUSY;

}}// enable interrupts// enable interrupts

}}

Lock::Release() {Lock::Release() {

// disable interrupts// disable interrupts

if (someone is waiting) {if (someone is waiting) {

// wake a thread// wake a thread

// Put it on ready // Put it on ready queuequeue

} else {} else {

value = FREE;value = FREE;

}}

// enable interrupts// enable interrupts

}}

Put the thread 2 on a waiting queue.

Locks Using Interrupt Disables, Locks Using Interrupt Disables, Without Busy-WaitingWithout Busy-Waiting

class Lock {class Lock {int value = FREE;int value = FREE;

}}

Lock::Acquire() {Lock::Acquire() {// disable interrupts// disable interruptsifif (value != FREE) { (value != FREE) {

// Queue the thread// Queue the thread// Go to sleep// Go to sleep

} else {} else {value = BUSY;value = BUSY;

}}// enable interrupts// enable interrupts

}}

Lock::Release() {Lock::Release() {

// disable interrupts// disable interrupts

if (someone is waiting) {if (someone is waiting) {

// wake a thread// wake a thread

// Put it on ready // Put it on ready queuequeue

} else {} else {

value = FREE;value = FREE;

}}

// enable interrupts// enable interrupts

}}

Sleep it off… Context switch;wait for someone to wake up the thread. zzzz

Locks Using Interrupt Disables, Locks Using Interrupt Disables, Without Busy-WaitingWithout Busy-Waiting

class Lock {class Lock {int value = FREE;int value = FREE;

}}

Lock::Acquire() {Lock::Acquire() {// disable interrupts// disable interruptsifif (value != FREE) { (value != FREE) {

// Queue the thread// Queue the thread// Go to sleep// Go to sleep

} else {} else {value = BUSY;value = BUSY;

}}// enable interrupts// enable interrupts

}}

Lock::Release() {Lock::Release() {

// disable interrupts// disable interrupts

if (someone is waiting) {if (someone is waiting) {

// wake a thread// wake a thread

// Put it on ready // Put it on ready queuequeue

} else {} else {

value = FREE;value = FREE;

}}

// enable interrupts// enable interrupts

}}

Say thread 1 wants to release the lock (interrupts are already disabled by thread 2).

Locks Using Interrupt Disables, Locks Using Interrupt Disables, Without Busy-WaitingWithout Busy-Waiting

class Lock {class Lock {int value = FREE;int value = FREE;

}}

Lock::Acquire() {Lock::Acquire() {// disable interrupts// disable interruptsifif (value != FREE) { (value != FREE) {

// Queue the thread// Queue the thread// Go to sleep// Go to sleep

} else {} else {value = BUSY;value = BUSY;

}}// enable interrupts// enable interrupts

}}

Lock::Release() {Lock::Release() {

// disable interrupts// disable interrupts

if (someone is waiting) {if (someone is waiting) {

// wake a thread// wake a thread

// Put it on ready // Put it on ready queuequeue

} else {} else {

value = FREE;value = FREE;

}}

// enable interrupts// enable interrupts

}}

Hello? Is someone waiting there? Thread 2 is waiting.

Locks Using Interrupt Disables, Locks Using Interrupt Disables, Without Busy-WaitingWithout Busy-Waiting

class Lock {class Lock {int value = FREE;int value = FREE;

}}

Lock::Acquire() {Lock::Acquire() {// disable interrupts// disable interruptsifif (value != FREE) { (value != FREE) {

// Queue the thread// Queue the thread// Go to sleep// Go to sleep

} else {} else {value = BUSY;value = BUSY;

}}// enable interrupts// enable interrupts

}}

Lock::Release() {Lock::Release() {

// disable interrupts// disable interrupts

if (someone is waiting) {if (someone is waiting) {

// wake a thread// wake a thread

// Put it on ready // Put it on ready queuequeue

} else {} else {

value = FREE;value = FREE;

}}

// enable interrupts// enable interrupts

}}

Put thread 2 on ready queue; context switch.

Locks Using Interrupt Disables, Locks Using Interrupt Disables, Without Busy-WaitingWithout Busy-Waiting

class Lock {class Lock {int value = FREE;int value = FREE;

}}

Lock::Acquire() {Lock::Acquire() {// disable interrupts// disable interruptsifif (value != FREE) { (value != FREE) {

// Queue the thread// Queue the thread// Go to sleep// Go to sleep

} else {} else {value = BUSY;value = BUSY;

}}// enable interrupts// enable interrupts

}}

Lock::Release() {Lock::Release() {

// disable interrupts// disable interrupts

if (someone is waiting) {if (someone is waiting) {

// wake a thread// wake a thread

// Put it on ready // Put it on ready queuequeue

} else {} else {

value = FREE;value = FREE;

}}

// enable interrupts// enable interrupts

}}

Thread 2: Who woke me? I don’t do mornings…

Locks Using Interrupt Disables, Locks Using Interrupt Disables, Without Busy-WaitingWithout Busy-Waiting

class Lock {class Lock {int value = FREE;int value = FREE;

}}

Lock::Acquire() {Lock::Acquire() {// disable interrupts// disable interruptsifif (value != FREE) { (value != FREE) {

// Queue the thread// Queue the thread// Go to sleep// Go to sleep

} else {} else {value = BUSY;value = BUSY;

}}// enable interrupts// enable interrupts

}}

Lock::Release() {Lock::Release() {

// disable interrupts// disable interrupts

if (someone is waiting) {if (someone is waiting) {

// wake a thread// wake a thread

// Put it on ready // Put it on ready queuequeue

} else {} else {

value = FREE;value = FREE;

}}

// enable interrupts// enable interrupts

}}

Thread 2 is done with its computation.

Locks Using Interrupt Disables, Locks Using Interrupt Disables, Without Busy-WaitingWithout Busy-Waiting

class Lock {class Lock {int value = FREE;int value = FREE;

}}

Lock::Acquire() {Lock::Acquire() {// disable interrupts// disable interruptsifif (value != FREE) { (value != FREE) {

// Queue the thread// Queue the thread// Go to sleep// Go to sleep

} else {} else {value = BUSY;value = BUSY;

}}// enable interrupts// enable interrupts

}}

Lock::Release() {Lock::Release() {

// disable interrupts// disable interrupts

if (someone is waiting) {if (someone is waiting) {

// wake a thread// wake a thread

// Put it on ready // Put it on ready queuequeue

} else {} else {

value = FREE;value = FREE;

}}

// enable interrupts// enable interrupts

}}

Suppose no one else is waiting.

Locks Using Interrupt Disables, Locks Using Interrupt Disables, Without Busy-WaitingWithout Busy-Waiting

class Lock {class Lock {int value = FREE;int value = FREE;

}}

Lock::Acquire() {Lock::Acquire() {// disable interrupts// disable interruptsifif (value != FREE) { (value != FREE) {

// Queue the thread// Queue the thread// Go to sleep// Go to sleep

} else {} else {value = BUSY;value = BUSY;

}}// enable interrupts// enable interrupts

}}

Lock::Release() {Lock::Release() {

// disable interrupts// disable interrupts

if (someone is waiting) {if (someone is waiting) {

// wake a thread// wake a thread

// Put it on ready // Put it on ready queuequeue

} else {} else {

value = FREE;value = FREE;

}}

// enable interrupts// enable interrupts

}}

Release the lock. (Thread 1 hasfinished its work, so it’s okay.)

Locks Using Interrupt Disables, Locks Using Interrupt Disables, Without Busy-WaitingWithout Busy-Waiting

class Lock {class Lock {int value = FREE;int value = FREE;

}}

Lock::Acquire() {Lock::Acquire() {// disable interrupts// disable interruptsifif (value != FREE) { (value != FREE) {

// Queue the thread// Queue the thread// Go to sleep// Go to sleep

} else {} else {value = BUSY;value = BUSY;

}}// enable interrupts// enable interrupts

}}

Lock::Release() {Lock::Release() {

// disable interrupts// disable interrupts

if (someone is waiting) {if (someone is waiting) {

// wake a thread// wake a thread

// Put it on ready // Put it on ready queuequeue

} else {} else {

value = FREE;value = FREE;

}}

// enable interrupts// enable interrupts

}}

Warp 9, engage (let’s get out of here)…

Locks Using Interrupt Disables, Locks Using Interrupt Disables, Without Busy-WaitingWithout Busy-Waiting

class Lock {class Lock {int value = FREE;int value = FREE;

}}

Lock::Acquire() {Lock::Acquire() {// disable interrupts// disable interruptsifif (value != FREE) { (value != FREE) {

// Queue the thread// Queue the thread// Go to sleep// Go to sleep

} else {} else {value = BUSY;value = BUSY;

}}// enable interrupts// enable interrupts

}}

Lock::Release() {Lock::Release() {

// disable interrupts// disable interrupts

if (someone is waiting) {if (someone is waiting) {

// wake a thread// wake a thread

// Put it on ready // Put it on ready queuequeue

} else {} else {

value = FREE;value = FREE;

}}

// enable interrupts// enable interrupts

}}

Eventually, the kernel will contextswitch back to thread 1.

What happened?

So, What’s Going On?So, What’s Going On?

Interrupt disable and enable Interrupt disable and enable operations occur across context operations occur across context switches (at the steady state)switches (at the steady state)

So, What’s Going On?So, What’s Going On?

Thread AThread A Thread BThread B

Disable interruptsSleep

Disable interruptsSleep

Return from sleepEnable interrupts

Context switch

Return from sleepEnable interrupts

Context switch

Locks Using Locks Using test_and_settest_and_set, With , With Minimal Busy-WaitingMinimal Busy-Waiting

Impossible to use Impossible to use test_and_settest_and_set to to avoid busy-waitingavoid busy-waiting

However, waiting can be minimized However, waiting can be minimized with a waiting queuewith a waiting queue

Locks Using Locks Using test_and_settest_and_set, With , With Minimal Busy-WaitingMinimal Busy-Waiting

class Lock {class Lock {int value = FREE;int value = FREE;

int guard = 0;int guard = 0;}}

Lock::Acquire() {Lock::Acquire() {while (test_and_set(guard));while (test_and_set(guard));if (value != FREE) {if (value != FREE) {

// queue the thread// queue the thread// guard = 0 and // guard = 0 and

sleepsleep} else {} else {

value = BUSY;value = BUSY;}}guard = 0;guard = 0;

}}

Lock::Release() {Lock::Release() {

while (test_and_set(guard));while (test_and_set(guard));

if (anyone waiting) {if (anyone waiting) {

// wake up one thread// wake up one thread

// put it on ready // put it on ready queuequeue

} else {} else {

value = FREE;value = FREE;

}}

guard = 0;guard = 0;

}}