2.1.5 Semaphores{Dijkstra 68}
• A synchronization tool which is
-- more elegant in construction
-- be implemented effectively in single and multiple processor systems.
• A semaphore is an integer variable S
-- is accessed only through two standard operations
P and V, or wait and signal
These names come from the Dutch proberen (to test) and verhogen (to increment)
• The classical definitions of P and V:
P(S): while S<=0 do no-op
S := S-1
V(S): S:= S+1
-- the modifications to S in the P and V operations are executed indivisibly:
that is when one process modifies the semaphore value, no other process can simultaneously modify that same semaphore value.
-- In P(S), the testing of the integer value of S(S<=0) and its possible modification (S := S-1), must also be executed without interruption.
• Implementation of P and V
-- A classical semaphore is called a "spinlock"
* useful in multiprocessor systems
* no context switch is required
-- overcome the busy-waiting situation:
[so CPU can be shared by other processes]
a process that is waiting on a semaphore S should be restarted by the execution of a S operation by some other process.
* define a semaphore as a record:
type semaphore = record
value: integer;
L: list of process;
end
* the semaphore operations can be defined as:
P(S): S.value := S.value -1
if S.value < 0
then begin
add this process to S.L
[the executing process places itself in S’s waiting group]
block;
[ relinquishes the CPU by invoking CPU scheduler]
V(S): S.value:= S.value +1
if S.value <=0
then begin
remove a process P from S.L
[S’s waiting group is nonempty then remove one waiting process ]
wakeup(p)
[and make it available for execution]
end
Note: Instead of queuing, we use waiting group to allow more general techniques for selecting processes.
5.4.1 Usage of Semaphores
[2.1. Common Synchronization Problems
]
• dealing with the n-process critical-section problem
• Mutual exclusion problem To implement critical sections among several processes sharing information, we need only one semaphore.
-- n processes share a common semaphore, mutex, initialized to 1.
-- Each process is organized as:
repeat
[P(mutex)]
critical section
[V(mutex)]
remainder section
until false;
var S: semaphore : = 1 (shared variable)
Process i Process J
loop loop
.... ....
{s = 0}
P(S); P(S);
{s = 0} { wait}
access shared data safely access shared data safely
V(S); V(S);
{make Pj available for ex.} {(queue is empty) s = 0+1}
.... ....
endloop endloop
• solving various synchronization problems
Ex,
-- two concurrently running processes: P1 with a statement S1 and P2 with a statement S2.
-- we require that S2 be executed only after S1 has completed.
-- a common semaphore "synch"
S1;
V(synch)
P(synch)
S2;
The three concurrent processes given below allocate and release their resources in the order shown, and the order cannot be changed. Using three counting semaphores (with Dijkstra P and V operations on them), design the appropriate synchronization for this system that satisfies the three conditions: mutual exclusion, progress and bounded waiting, and maximizes concurrency (or overlap).
Define your semaphores as A, B, C and show where the P and V operations on them should be inserted in the process code between the allocations and releases. Assume that time passes between each of the steps shown below:
Process 1 Process 2 Process 3
Allocate Disk1 Allocate Disk2 Allocate Tape 1
Allocate tape 1 Allocate Plotter Release Tape 1
Release Disk 1 Allocate Printer Allocate Plotter
Allocate Disk2 Release all resources Allocate Disk3
Release all resources Release all resources
Allocate Printer
Release Printer
Allocate Plotter
Release Plotter