SEMAPHORES
SEMAPHORES
The various hardware-based solutions to the critical-section problem (using the TestAndSet() and Swap()
instructions) presented in Section 6.4 are complicated for application programmers to use. To overcome
this difficulty, we can use synchronization tool called semaphore.
A semaphore S is an integer variable that, apart from initialization, is accessed only through two
standard atomic operations: wait() and signal(). The wait() operation was originally termed P (from the
Dutch proberen, “to test”); signal() was originally called V (from verhogen, “to increment”). The
definition of wait() is as follows:
wait(S) {
while S < = 0
t // no-cp
S--t
}
signal(S) {
S++t
}
All modifications to the integer value of the semaphore in the wait(0 and signal() operations
must be executed indivisibly. That is, when one process modifies the semaphore value, no other process
can simultaneously modify the same semaphore value. In addition, in the case of wait(S), the testing of
the integer value of S (S ≤ 0), and its possible modification (S--) must also be executed without
interruption. We shall see how these operations can be implemented in Section 6.5.2; first, let us see
how semaphores can be used.
do {
waiting(mutex) ;
// critical section
signal(mutex);
// remainder section
}while (TRUE);
6.5.1 Usage
Opearating systems often distinguish between counting and binary semaphores. The value of a counting
semaphore can range over an unrestricted domain. The value of a binary semaphore can range only
between 0 and 1. On some systems, binary semaphores are known as mutex , as they are locks that
provide mutual exclusion.
We can use binary semaphores to deal with the critical-section problem for multiple processes.
The n processes share a semaphore, mutex, initialized to 1. Each process P i organized as shown in Figure
6.11.
Counting semaphores can be used to control access to a given resource consisting of a finite
number of instances. The semaphore is initialized to the number of resources available. Each process
that wishes to use a resource performs a wait() operation on the semaphore (thereby decrementing the
count). When a process releases a resource, it performs a signal() operation (incrementing the count).
When the count for the semaphore goes to 0, all resources are being used. After that, processes that
wish to use a resource will block until the count becomes greater than 0.
We can also use semaphores to solve various synchronization problems. For example, consider
two concurrently running processes: P1 with a statement S1 and P1 with a statement S2. Suppose we
require that S2 be executed only after S1 has completed. We can implement this scheme readily by letting
P1 and P2 share a common semaphore synch, initialized to 0, and by inserting the statements.
S1;
Signal(synch);
wait(synch);
S2;
in process P2. Because synch is initialized to 0, P2 will execute S2 only after P1 has invoked signal(synch),
which is after statement S1 has been executed.