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