Information Technology Reference
In-Depth Information
Semaphores considered harmful. 4 Our view is that programming with locks
and condition variables is superior to programming with semaphores, and we advise
you to always write your code using those synchronization variables for two reasons.
First, using separate lock and condition variable classes makes code more self-
documenting and easier to read. As the quote from Dijkstra above notes, there really
are two abstractions here, and code is clearer when the role of each synchronization
variable is made clear through explicit typing.
Second, a stateless condition variable bound to a lock turns out to be a better ab-
straction for generalized waiting than a semaphore. By binding a condition variable to
a lock, we can conveniently wait on any arbitrary predicate on an object's state. In con-
trast, semaphores rely on carefully mapping the object's state to the semaphore's value
so that a decision to wait or proceed in P() can be made entirely based on the value ,
without holding a lock or examining the rest of the shared object's state.
Although we do not recommend writing new code with semaphores, code based
on semaphores are not uncommon, especially in operating systems. So, it is impor-
tant to understand the semantics of semaphores and be able to read and understand
semaphore-based code written by others.
One exception. There is one situation in which semaphores are often superior
to condition variables and locks: synchronizing communication between an I/O device
and threads running on the processor. In this situation, there is often a data structure
shared by the hardware device and the operating system software, and it is often not
possible to require the hardware to acquire a lock on that data structure before updating
it. Instead, the data structure, hardware, and device drivers are designed to work with
carefully-ordered atomic memory operations.
If a hardware device needs attention, it updates the shared data structure and then
may need to cause some waiting operating system thread to run.
To trigger this waiting thread, one might consider using a condition variable and
calling Signal() without holding the lock (this is sometimes called a naked notify.) Un-
fortunately, there is a corner case: suppose that the operating system thread first checks
the data structure, sees that no work is currently needed, and is just about to call Wait()
on the condition variable. At that moment, the hardware updates the data structure with
the new work and calls Signal() . Thus, when the thread calls Wait() , the signal has
already occurred and the thread waits—possibly for a long time.
The solution is for devices to enable operating system threads using semaphores
instead. Because semaphores are stateful, a Signal() (or V() ) cannot be lost. A
common approach is for the hardware to send information to the software thread via a
bounded queue that is synchronized using semaphores.
4 Edsger Dijkstra is the author of the short note \Go To Statement Considered Harmful",
CommunicationsoftheACM, v. 11 n. 3, March 1968, pp 147{148.
Search WWH ::




Custom Search