Lec08 Readerwriter
Lec08 Readerwriter
Readers-Writers
Language Support for Synchronization
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
– Why
2/13/06 can’t we do it CS162
Joseph just ©UCB
before
Springor just after the sleep?
2006 Lec 8.4
Review: Semaphores
• Definition: a Semaphore has a non-negative integer
value and supports the following two operations:
– P(): an atomic operation that waits for semaphore to
become positive, then decrements it by 1
» Think of this as the wait() operation
– V(): an atomic operation that increments the semaphore
by 1, waking up a waiting P, if any
» This of this as the signal() operation
– Only time can set integer directly is at initialization time
• Semaphore from railway analogy
– Here is a semaphore initialized to 2 for resource control:
Value=2
Value=0
Value=1
2/13/06 Joseph CS162 ©UCB Spring 2006 Lec 8.5
Review: Producer-consumer with a bounded buffer
• Problem Definition
– Producer puts things into a shared buffer (wait if full)
– Consumer takes them out (wait if empty)
– Use a fixed-size buffer between them to avoid lockstep
» Need to synchronize access to this buffer
• Correctness Constraints:
– Consumer must wait for producer to fill buffers, if none full
(scheduling constraint)
– Producer must wait for consumer to empty buffers, if all full
(scheduling constraint)
– Only one thread can manipulate buffer queue at a time (mutual
exclusion)
• Remember why we need mutual exclusion
– Because computers are stupid
• General rule of thumb:
Use a separate semaphore for each constraint
– Semaphore fullBuffers; // consumer’s constraint
– Semaphore emptyBuffers;// producer’s constraint
– Semaphore mutex; // mutual exclusion
2/13/06 Joseph CS162 ©UCB Spring 2006 Lec 8.6
Goals for Today
next
New
Object
2/13/06 Joseph CS162 ©UCB Spring 2006 Lec 8.8
Motivation for Monitors and Condition Variables
• Semaphores are a huge step up, but:
– They are confusing because they are dual purpose:
» Both mutual exclusion and scheduling constraints
» Example: the fact that flipping of P’s in bounded buffer
gives deadlock is not immediately obvious
– Cleaner idea: Use locks for mutual exclusion and
condition variables for scheduling constraints
• Definition: Monitor: a lock and zero or more condition
variables for managing concurrent access to shared
data
– Use of Monitors is a programming paradigm
– Some languages like Java provide monitors in the
language
• The lock provides mutual exclusion to shared data:
– Always acquire before accessing shared data structure
– Always release after finishing with shared data
– Lock initially free
2/13/06 Joseph CS162 ©UCB Spring 2006 Lec 8.9
Simple Monitor Example (version 1)
• Here is an (infinite) synchronized queue
Lock lock;
Queue queue;
AddToQueue(item) {
lock.Acquire(); // Lock shared data
queue.enqueue(item); // Add item
lock.Release(); // Release Lock
}
RemoveFromQueue() {
lock.Acquire(); // Lock shared data
item = queue.dequeue();// Get next item or null
lock.Release(); // Release Lock
return(item); // Might return null
}
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/13/06 Joseph CS162 ©UCB Spring 2006 Lec 8.12
Mesa vs. Hoare monitors
• Need to be careful about precise definition of signal
and wait. Consider a piece of our dequeue code:
while (queue.isEmpty()) {
dataready.wait(&lock); // If nothing, sleep
}
item = queue.dequeue(); // Get next item
– Why didn’t we do this?
if (queue.isEmpty()) {
dataready.wait(&lock); // If nothing, sleep
}
item = queue.dequeue(); // Get next item
• Answer: depends on the type of scheduling
– Hoare-style (most textbooks):
» Signaler gives lock, CPU to waiter; waiter runs immediately
» Waiter gives up lock, processor back to signaler when it
exits critical section or if it waits again
– Mesa-style (Nachos, most real operating systems):
» Signaler keeps lock and processor
» Waiter placed on ready queue with no special priority
» Practically, need to check condition again after wait
2/13/06 Joseph CS162 ©UCB Spring 2006 Lec 8.13
Administrivia
R
R
R
void DoFoo() {
…
if (exception) throw errException;
…
}
2/13/06 Joseph CS162 ©UCB Spring 2006 Lec 8.29
Java Language Support for Synchronization