Lec07 Exclusion
Lec07 Exclusion
February 8, 2006
Prof. Anthony D. Joseph
http://inst.eecs.berkeley.edu/~cs162
Review: A Concurrent Program Example
• Two threads, A and B, compete with each other
– One tries to increment a shared counter
– The other tries to decrement the counter
Thread A Thread B
i = 0; i = 0;
while (i < 10) while (i > -10)
i = i + 1; i = i – 1;
printf(“A wins!”); printf(“B wins!”);
• Assume that memory loads and stores are atomic, but
incrementing and decrementing are not atomic
• Who wins? Could be either
• Is it guaranteed that someone wins? Why or why not?
• What it both threads have their own CPU running at
same speed? Is it guaranteed that it goes on
forever?
2/8/06 Joseph CS162 ©UCB Spring 2006 Lec 7.2
Review: Hand Simulating Multiprocessor Example
• Inner loop looks like this:
Thread A Thread B
r1=0 load r1, M[i]
r1=0 load r1, M[i]
r1=1 add r1, r1, 1
r1=-1 sub r1, r1, 1
M[i]=1 store r1, M[i]
M[i]=-1 store r1, M[i]
Hand Simulation:
– And we’re off. A gets off to an early start
– B says “hmph, better go fast” and tries really hard
– A goes ahead and writes “1”
– B goes and writes “-1”
– A says “HUH??? I could have sworn I put a 1 there”
• Could this happen on a uniprocessor?
– Yes! Unlikely, but if you depending on it not happening,
it will and your system will break…
2/8/06 Joseph CS162 ©UCB Spring 2006 Lec 7.3
Review: Too Much Milk Solution #3
• Here is a possible two-note solution:
Thread A Thread B
leave note A; leave note B;
while (note B) {\\X if (noNote A) {\\Y
do nothing; if (noMilk) {
} buy milk;
if (noMilk) { }
buy milk; }
} remove note B;
remove note A;
• Does this work? Yes. Both can guarantee that:
– It is safe to buy, or
– Other will buy, ok to quit
• At X:
– if no note B, safe for A to buy,
– otherwise wait to find out what will happen
• At Y:
– if no note A, safe for B to buy
– Otherwise, A is either buying or waiting for B to quit
2/8/06 Joseph CS162 ©UCB Spring 2006 Lec 7.4
Goals for Today
Higher-
level Locks Semaphores Monitors Send/Receive
API
Acquire() { Release() {
disable interrupts; disable interrupts;
if (value == BUSY) { if (anyone on wait queue) {
put thread on wait queue; take thread off wait queue
Go to sleep(); Place on ready queue;
// Enable interrupts? } else {
value = FREE;
} else {
}
value = BUSY; enable interrupts;
} }
enable interrupts;
}
Acquire() { Release() {
// Short busy-wait time // Short busy-wait time
while (test&set(guard)); while (test&set(guard));
if (value == BUSY) { if anyone on wait queue {
take thread off wait queue
put thread on wait queue; Place on ready queue;
go to sleep() & guard = 0; } else {
} else { value = FREE;
value = BUSY; }
guard = 0; guard = 0;
}
}
• Note: sleep has to be sure to reset the guard
variable
2/8/06– Why can’t we do it CS162
Joseph just ©UCB
before
Springor just after the sleep?
2006 Lec 7.20
Higher-level Primitives than Locks
• Goal of last couple of lectures:
– What is the right abstraction for synchronizing threads
that share memory?
– Want as high a level primitive as possible
• Good primitives and practices important!
– Since execution is not entirely sequential, really hard to
find bugs, since they happen rarely
– UNIX is pretty stable now, but up until about mid-80s
(10 years after started), systems running UNIX would
crash every week or so – concurrency bugs
• Synchronization is a way of coordinating multiple
concurrent activities that are using shared state
– This lecture and the next presents a couple of ways of
structuring the sharing
Value=2
0
1
Producer(item) {
emptyBuffers.P(); // Wait until space
mutex.P(); // Wait until buffer free
Enqueue(item);
mutex.V();
fullBuffers.V(); // Tell consumers there is
// more coke
}
Consumer() {
fullBuffers.P(); // Check if there’s a coke
mutex.P(); // Wait until machine free
item = Dequeue();
mutex.V();
emptyBuffers.V(); // tell producer need more
return item;
}
2/8/06 Joseph CS162 ©UCB Spring 2006 Lec 7.28
Discussion about Solution
• Why asymmetry?
– Producer does: emptyBuffer.P(), fullBuffer.V()
– Consumer does: fullBuffer.P(), emptyBuffer.V()
• Is order of P’s important?
– Yes! Can cause deadlock
• Is order of V’s important?
– No, except that it might affect scheduling efficiency
• What if we have 2 producers or 2 consumers?
– Do we need to change anything?
AddToQueue(item) {
lock.Acquire(); // Get Lock
queue.enqueue(item); // Add item
dataready.signal(); // Signal any waiters
lock.Release(); // Release Lock
}
RemoveFromQueue() {
lock.Acquire(); // Get Lock
while (queue.isEmpty()) {
dataready.wait(&lock); // If nothing, sleep
}
item = queue.dequeue(); // Get next item
lock.Release(); // Release Lock
return(item);
}
2/8/06 Joseph CS162 ©UCB Spring 2006 Lec 7.32
Summary
• Important concept: Atomic Operations
– An operation that runs to completion or not at all
– These are the primitives on which to construct various
synchronization primitives
• Talked about hardware atomicity primitives:
– Disabling of Interrupts, test&set, swap, comp&swap,
load-linked/store conditional
• Showed several constructions of Locks
– Must be very careful not to waste/tie up machine
resources
» Shouldn’t disable interrupts for long
» Shouldn’t spin wait for long
– Key idea: Separate lock variable, use hardware
mechanisms to protect modifications of that variable
• Talked about Semaphores, Monitors, and Condition
Variables
– Higher level constructs that are harder to “screw up”
2/8/06 Joseph CS162 ©UCB Spring 2006 Lec 7.33