Download as pdf or txt
Download as pdf or txt
You are on page 1of 2

Semaphores — OS Support for From Semaphores to

Mutual Exclusion (Review) Locks and Condition Variables

n Even with semaphores, some n A semaphore serves two purposes:


synchronization errors can occur: ● Mutual exclusion — protect shared data
Honest Mistake Careless Mistake n mutex in Coke machine
n milk in Too Much Milk
milk–>V( ); milk–>P( );
n Always a binary semaphore
if (noMilk) if (noMilk)
buy milk; buy milk; ● Synchronization — temporally coordinate
milk–>P( ); milk–>P( ); events (one thread waits for something,
● Other variations possible other thread signals when it’s available)
n fullSlot and emptySlot in Coke machine
n Solution — new language constructs n Either a binary or counting semaphore

● (Conditional) Critical region n Idea — two separate constructs:


n region v when B do S;
n Variable v is a shared variable that can ● Locks — provide mutually exclusion
only be accessed inside the critical region ● Condition variables — provide
n Boolean expression B governs access synchronization
n Statement S ( critical region) is executed
only if B is true; otherwise it blocks until B ● Like semaphores, locks and condition
does become true variables are language-independent, and
are available in many programming
● Monitor environments
1 Fall 1998, Lecture 13 2 Fall 1998, Lecture 13

Locks Locks (cont.)

n Locks provide mutually exclusive access n Conventions:


to shared data: ● Before accessing shared data, call
● A lock can be “locked” or “unlocked” Lock::Acquire( ) on a specific lock
(sometimes called “busy” and “free”) n Complain (via ASSERT) if a thread tries to
Acquire a lock it already has
n Operations on locks (Nachos syntax): ● After accessing shared data, call Lock::
● Lock(*name) — create a new (initially Release( ) on that same lock
unlocked) Lock with the specified name n Complain if a thread besides the one that
Acquired a lock tries to Release it
● Lock::Acquire( ) — wait (block) until the
lock is unlocked; then lock it n Example of using locks for mutual
● Lock::Release( ) — unlock the lock; then exclusion (here, “milk” is a lock):
wake up (signal) any threads waiting on it
in Lock::Acquire( ) Thread A Thread B
milk–>Acquire( ); milk–>Acquire( );
n Can be implemented: if (noMilk) if (noMilk)
buy milk; buy milk;
● Trivially by binary semaphores (create a milk–>Release( ); milk–>Release( );
private lock semaphore, use P and V)
● The test in threads/threadtest.cc should
● By lower-level constructs, much like work exactly the same if locks are used
semaphores are implemented instead of semaphores
3 Fall 1998, Lecture 13 4 Fall 1998, Lecture 13
Locks vs. Condition Variables Condition Variables

n Consider the following code: n Condition variables coordinate events


Queue::Add( ) { Queue::Remove( ) {
lock->Acquire( ); lock->Acquire( ); n Operations on condition variables
add item if item on queue (Nachos syntax):
lock->Release( ); remove item
} lock->Release( ); ● Condition(*name) — create a new
return item; instance of class Condition (a condition
} variable) with the specified name
n After creating a new condition, the
● Queue::Remove will only return an item if
programmer must call Lock::Lock( ) to
there’s already one in the queue create a lock that will be associated with
that condition variable
n If the queue is empty, it might be more
● Condition::Wait(conditionLock) — release
desirable for Queue::Remove to wait until
the lock and wait (sleep); when the thread
there is something to remove wakes up, immediately try to re-acquire
● Can’t just go to sleep — if it sleeps while the lock; return when it has the lock
holding the lock, no other thread can ● Condition::Signal(conditionLock) — if
access the shared queue, add an item to threads are waiting on the lock, wake up
it, and wake up the sleeping thread one of those threads and put it on the
● Solution: condition variables will let a ready list; otherwise do nothing
thread sleep inside a critical section, by
releasing the lock while the thread sleeps
5 Fall 1998, Lecture 13 6 Fall 1998, Lecture 13

Condition Variables (cont.) Using Locks and Condition Variables

n Operations (cont.): n Associated with a data structure is both a


● Condition::Broadcast(conditionLock) — if
lock and a condition variable
threads are waiting on the lock, wake up ● Before the program performs an operation
all of those threads and put them on the on the data structure, it acquires the lock
ready list; otherwise do nothing
● If it needs to wait until another operation
puts the data structure into an appropriate
n Important: a thread must hold the lock state, it uses the condition variable to wait
before calling Wait, Signal, or Broadcast
n Unbounded-buffer producer-consumer:
n Can be implemented:
Lock *lk; int avail = 0;
● Carefully by higher-level constructs Condition *c;
(create and queue threads, sleep and /* consumer */
wake up threads as appropriate) /* producer */ while (1) {
● Carefully by binary semaphores (create while (1) { lk-> Acquire( );
and queue semaphores as appropriate, lk->Acquire( ); if (avail==0)
use P and V to synchronize) produce next item c->Wait(lk);
n Does this work? More on this in a few avail++; consume next item
minutes… c->Signal(lk) avail--;
lk->Release( ); lk->Release( );
● Carefully by lower-level constructs, much } }
like semaphores are implemented
7 Fall 1998, Lecture 13 8 Fall 1998, Lecture 13

You might also like