0% found this document useful (0 votes)
11 views4 pages

Semaphores: Arvind Krishnamurthy Spring 2001

The document discusses semaphores, monitors, and condition variables which are synchronization primitives used for managing access to shared resources and scheduling threads. Semaphores use two atomic operations P and V to control access and can be used for both mutual exclusion and scheduling. Monitors combine locks and condition variables to make synchronization easier by separating concerns of mutual exclusion and scheduling.

Uploaded by

hoang.van.tuan
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
11 views4 pages

Semaphores: Arvind Krishnamurthy Spring 2001

The document discusses semaphores, monitors, and condition variables which are synchronization primitives used for managing access to shared resources and scheduling threads. Semaphores use two atomic operations P and V to control access and can be used for both mutual exclusion and scheduling. Monitors combine locks and condition variables to make synchronization easier by separating concerns of mutual exclusion and scheduling.

Uploaded by

hoang.van.tuan
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 4

Semaphores

n Two atomic operations:


n P: decrement
n V: increment

Monitors and Condition Variables n Used for mutual exclusion:


n Value = 0 means locked
n Value = 1 means unlocked
n P is equivalent to locking, V is equivalent to unlocking
Arvind Krishnamurthy n Initialized to 1 usually
Spring 2001
n Used for scheduling:
n Value = 0 means condition has not been met
n Value = 1 means condition to schedule the next task has been achieved
n Initialized to 0 usually

Producer-consumer with Producer-consumer with


semaphores (1) semaphores (2)
n Correctness constraints Semaphore fullBuffers = 0; // initially no coke
n consumer must wait for at least one buffer to be full (scheduling Semaphore emptyBuffers = numBuffers;
constraints) // initially, # of empty slots semaphore used to Consumer() {
// count how many resources there are fullBuffers.P(); // check if there is
n producer must wait for at least one buffer to become empty
Semaphore mutex = 1; // no one using the machine // a coke in the machine
(scheduling constaints) mutex.P(); // make sure no one
n Only one thread can manipulate buffer queue at a time (mutual Producer() { // else is using machine
exclusion) emptyBuffers.P(); // check if there is space
// for more coke take 1 Coke out;
mutex.P(); // make sure no one else
n General rule of thumb: use a separate semaphore for each constraint // is using machine mutex.V(); // next person’s turn

Semaphore fullBuffers; // consumer’s constraint emptyBuffers.V(); // tell producer


put 1 Coke in machine; // we need more
// if 0, no coke in machine }
Semaphore emptyBuffers; // producer’s constraint mutex.V(); // ok for others to use machine

// if 0, nowhere to put more coke fullBuffers.V(); // tell consumers there is now


// a Coke in the machine What if we have 2 producers and 2
Semaphore mutex; // mutual exclusion } consumers?

Order of P&Vs Monitors & condition variables


Semaphore fullBuffers = 0; // initially no coke n Limitations of semaphores
Semaphore emptyBuffers = numBuffers;
n dual purpose: mutual exclusion and scheduling constraints.
// initially, # of empty slots semaphore used to Consumer() {
// count how many resources there are mutex.P(); // make sure no one n order of P&Vs matters! Can lead to deadlock.
Semaphore mutex = 1; // no one using the machine // else is using machin
fullBuffers.P(); // check if there is
Producer() { // a coke in the machine n Monitors make things easier:
mutex.P(); // make sure no one else
// is using machine take 1 Coke out; n “locks” for mutual exclusion
emptyBuffers.P(); // check if there is space n “condition variables” for scheduling constraints
// for more coke emptyBuffers.V(); // tell producer
// we need more
put 1 Coke in machine; mutex.V();
}
// next person’s turn
n Monitor definition:
fullBuffers.V(); // tell consumers there is now n a lock and zero or more condition variables for managing
// a Coke in the machine
Deadlock---two or more processes are concurrent access to shared data
mutex.V(); // ok for others to use machine
waiting indefinitely for an event that
}
can be caused by only one of the
waiting processes.

1
How to use the lock ? Condition variables
n The lock provides mutual exclusion to the shared data n How to make RemoveFromQueue wait until something is on the
n Rules for using a lock: queue?
n Always acquire before accessing shared data structure n can’t sleep while holding the lock
n Always release after finishing with shared data n Key idea: make it possible to go to sleep inside critical section, by
atomically releasing lock at same time we go to sleep.
n Lock is initially free

n Simple example: a synchronized list n Condition variable: a queue of threads waiting for
something inside a critical section.
RemoveFromQueue() n Wait() --- Release lock, go to sleep, re-acquire lock
AddToQueue() {
{ lock.Acquire(); n release lock and going to sleep is atomic
lock.Acquire(); // lock before use if something on queue // can we wait?
put item on queue; // ok to access remove it;
n Signal() --- Wake up a waiter, if any
lock.Release(); // unlock after done lock->Release();
}
n Broadcast() --- Wake up all waiters
return item;
}

Synchronized queue Mesa-style vs. Hoare-style


n Rule: must hold lock when doing condition variable n Mesa-style (Nachos, most real OS):
operations n Signaler keeps lock, processor
n Waiter simply put on ready queue, with no special priority
RemoveFromQueue() (in other words, waiter may have to wait for lock again)
AddToQueue() {
{ lock.Acquire();
lock.Acquire(); n Hoare-style (most theory, textbook):
while nothing on queue
Signaler passes lock, CPU to waiter; waiter runs immediately
condition.wait(&lock);
n
put item on queue;
condition.signal(); // release lock; go to n Waiter gives lock, processor back to signaler when it exits critical
// sleep; reacquire lock section or if it waits again
lock.Release();
} remove item from queue;
lock->Release(); n For Mesa-semantics, you always need to check the
return item; condition after wait (use “while”). For Hoare-semantics you
}
can change it to “if”

Using Mesa-style monitors Monitors Support in Languages


n Monitor represents the logic of the program n High-level data abstraction that unifies handling of:
n wait if necessary, n Shared data, operations on it, synch and scheduling
n signal if change something so waiter might need to wait up. n All operations on data structure have single (implicit) lock

n An operation can relinquish control and wait on condition

// only one process at time can update instance of Q


class Q {
lock; int head, tail; // shared data
while (need to wait) { lock; synchronized void enq(v) { locked access to Q instance }
wait(); do something; synchronized int deq() { locked access to Q instance }
}
} signal();
n Java from Sun; Mesa/Cedar from Xerox PARC
unlock unlock;

n Monitors easier and safer than semaphores


n Compiler can check, lock implicit (cannot be forgotten)

2
Implementing Monitors Producer-consumer with monitors
Condition full;
Condition empty;
n Wait() Queues Lock lock;

n Block on “condition” associated x Producer() { Consumer() {


n Signal() with x, y y lock.Acquire(); lock.Acquire();
n Wakeup a blocked conditions Shared
process on “condition” while (the buffer is full) while (the buffer is empty)
data full.wait(&lock); empty.wait(&lock);

put 1 Coke in machine; take 1 Coke;

... if (the buffer was empty) if (the buffer was full)


Entry queue empty.signal(); full.signal();
lock.Release(); lock.Release();
operations
} }

Summary Question 1:
n Template for using monitors: n Why does wait need to be an atomic “unlock + sleep”
operation?

lock.Acquire(); lock.Acquire(); lock.Acquire(); lock.Acquire();

while (!ready) { ready = 1; while (!ready) { ready = 1;


wait(cond); lock.Release();
} signal(cond); sleep on cond; signal(cond);
}
lock.Release(); lock.Release(); lock.Release();
lock.Release();

Question 2: Question 3:
n If wait does not automatically acquire the lock when it n Does the waker require mutex?
returns, does that lead to errors?

lock.Acquire(); lock.Acquire(); lock.Acquire();

while (!ready) { ready = 1; while (!ready) {


wait(cond); wait(cond); ready = 1;
lock.Acquire(); signal(cond); }
} signal(cond);
lock.Release(); lock.Release();
lock.Release();

3
Question 4: Readers/writers problem
n Is it correct to: change state with mutex, but signal without n Motivation
the lock? n shared database (e.g., bank balances / airline seats)
n Two classes of users:
n Readers --- never modify database

lock.Acquire(); lock.Acquire();
n Writers --- read and modify database

n Using a single lock on the database would be overly restrictive


while (!ready) { ready = 1;
n want many readers at the same time

wait(cond); n only one writer at the same time

} lock.Release();

n Constraints
lock.Release(); signal(cond);
n Readers can access database when no writers (Condition okToRead)
n Writers can access database when no readers or writers (Condition
okToWrite)
n Only one thread manipulates state variable at a time

Design Specification Solving readers/writers


n Reader Reader() { Writer() {
n wait until no writers // first check self into system // first check self into system
lock.Acquire(); lock.Acquire();
n access database while ((AW+WW) > 0) { while ((AW+AR) > 0) {
n check out - wake up waiting writer WR ++;
WW ++;
okToRead.Wait(&lock);
n Writer WR --;
okToWrite.Wait(&lock);
wait until no readers or writers WW --;
n }
AR++; }
n access data base AW++;
lock.Release();
n check out --- wake up waiting readers or writer lock.Release();
Access DB;
Access DB;
// check self out of system
n State variables lock.Acquire(); // check self out of system
n # of active readers (AR); # of active writers (AW); AR--; lock.Acquire();
if (AR == 0 && WW > 0)
n # of waiting readers (WR); # of waiting writers (WW); AW--;
okToWrite.Signal(&lock); if (WW > 0) okToWrite.Signal(&lock);
lock.Release();
else if (WR > 0) okToRead.Broadcast(&lock);
}
n Lock and condition variables: okToRead, okToWrite lock.Release();
}

You might also like