Problems with previously discussed methods:
- not easily generalized
- not easy to apply to other types of problems
Semaphores
A semaphore is an integer variable which can only be accessed through
two atomic operations: wait (also called P or down) and signal (also called V or up).
The idea:
wait(S):
while (S <= 0) ;
S = S -1;
signal(S):
S = S + 1;
In what sense are these atomic?
Standard ways to use a semaphore:
Protect a critical section:
S is initialized to 1:
wait(S);
<C.S.>
signal(S);
<R.S.>
Make sure P
1 executes before P
2:
S initialized to 0:
P
1:
<do something>
signal(S);
P
2:
wait(S);
<do something>
Semaphores and busy waiting
How an operating system can implement semaphores without busy waiting
The idea:
- When a process begins waiting, it should be removed from the CPU.
- It goes into a special queue of processes waiting for a semaphore
- This is like an I/O waiting queue.
- The OS will manage this queue (say as a FIFO queue) and remove a process
when a signal occurs.
- A semaphore will now be a record consisting of an integer (S.value)
and a linked list of waiting processes (S.list).
- If the integer is 0 or negative, its magnitude is the number of
processes waiting for this semaphore.
- It is initialized to have 0 value and empty list.
wait(S):
S.value--;
if (S.value < 0) {
<Add this process to S.list>
<block>
}
signal(S):
S.value++;
if (S.value <= 0) {
<move a process from S.list to the ready list>
}
Note: the type of queue we use will determine the order in which processes
which are waiting for a given semaphore get serviced.
A FIFO queue guarantees bounded waiting, but other queue techniques may produce
starvation.
Semaphores and the critical section problem
Care must be taken when dealing with semaphores:
Consider two processes P
1 and P
2.
P
1 executes:
while P
2 executes:
Each is waiting for the other and if the semaphores are both initialized to
0, a deadlock can occur.
Bounded buffer problem using semaphores
Assume we have n buffers.
Use three semaphores:
- mutex initialized to 1 (used for mutual exclusion)
- empty initialized to n (keeps track of the number of empty slots)
- full initialized to 0 (keeps track of the number of full slots)
Producer Loop:
produce item in nextp
wait(empty)
wait(mutex)
<add nextp to buffer>
signal(mutex)
signal(full)
Consumer Loop
wait(full)
wait(mutex)
<remove item from buffer, put in nextp>
signal(mutex)
signal(empty)
consume item in nextp
Semaphores and the Bounded Buffer Problem
Next Notes
Back to CS 3733 Notes Table of Contents