1 semaphores n semaphores issues addressed: 1. problems with busy-waiting 2. definition of a...
DESCRIPTION
Semaphores n The concept of a semaphore is motivated by one of the ways in which railroad traffic is synchronized to avoid train collisions. n A railroad semaphore is a signal flag that indicates whether the track ahead is clear or is occupied by another train. n As a train proceeds, semaphores are set and cleared; they remain set long enough to allow another train time to stop if necessary. 3 Semaphores in concurrent programming are similar: They provide a basic signalling mechanism and are used to implement mutual exclusion and condition synchronizationTRANSCRIPT
1
Semaphores Semaphores
Issues addressed: 1. Problems with busy-waiting 2. Definition of a semaphore: init(s), P(s) and V(s) - invariant 3. Examples
Critical Section Problem; Producers and Consumers Bounded Buffer; Dining Philosophers Databases - Readers and Writers Scheduling - barriers; SJN
2
Semaphores Introduction
Busy Waiting Problems 1. Synchronising variables look like ordinary variables. 2. Busy-wait is inefficient because processor cycles are wasted reading
locks. 3. Can't guarantee fairness
Because Synchronization is fundamental to concurrent programs, it is desirable to have special tools that aid in the design of correct synchronization protocols and that can be used to block processes that must be delayed
Semaphores were the first and remain one of the most important synchronization tools
3
Semaphores The concept of a semaphore is motivated by one of the ways in which
railroad traffic is synchronized to avoid train collisions. A railroad semaphore is a signal flag that indicates whether the track
ahead is clear or is occupied by another train. As a train proceeds, semaphores are set and cleared; they remain set
long enough to allow another train time to stop if necessary.
Semaphores in concurrent programming are similar: They provide a basic signalling mechanism and are used to implement mutual exclusion and condition synchronization
4
Semaphores A Semaphore is a special kind of shared variable that is manipulated
only by two atomic operations P and V.
The value of a semaphore is a nonnegative integer.
The V operation is used to signal the occurrence of an event, so it increments the value of a semaphore.
The P operation is used to delay a process until an event has occurred, so it waits until the value of the semaphore is positive then decrements the value.
The letter P and V are mnemonics for Dutch words, think of P as standing for pass, and think of the upward shape of V as signifying increment
5
Semaphores Advantages of Semaphores
1. Special variables used for synchronisation 2. Implemented in O/S kernel without wasting processor cycles.
Real-World Analogy Purchase a cardboard box. Call it s. Put n pieces of paper into it. A
person gets a piece of paper from s. Call this operation P(s). (The number of pieces of paper in the box decreases by one.) A person puts a piece of paper into the box. Call this operation V(s). (The number of pieces of paper in the box increases by one.) Never allow the total number of pieces of paper in circulation to change.
6
Semaphores General Semaphore
A semaphore, s, is an object which is manipulated by two operations P(s) and V(s). It has an initial integer value, init.
Invariant Define the following:
nP - the number of completed P operationsnV - the number of completed V operationsinit - the initial value of the semaphore
Let the expression S be:S = init + nV - nP
Then the semaphore invariant SEM is: SEM: S 0 Because a P operation increases nP by 1, (which decreases init by 1),
then if S ==0 after P it must be greater than 0 before P.
7
Semaphores After a semaphore has been declared and initialised, it can be
manipulated only by using the P and V operations.
Let s be a semaphore, then the definitions of P(s) and V(s) are: P(S): < await (S>0) s=s-1;> V(s): < s = s+1; >
The V operation atomically increments the value of S. The P operation decrements the value of s, but to ensure that s in never negative, the operation P waits until s is positive.
The delay and decrement in the P operation are a single atomic action.
AtomicAtomic
8
Semaphores Suppose s is a semaphore with current value 1:
1) If two processes try at the same time to execute P(s) operations, only one process will succeed.
2) If one process try to execute P(s) at the same time tht another process tries to execute V(s), the two operations will both success – in an unpredictable order – and the final value of s will again be 1.
A general semaphore is one that can take on any nonnegative value
9
Semaphores Binary Semaphore
This is a semaphore, b, in which the value of the semaphore is only ever 0 or 1. The invariant is: BSEM: 0 b 1
In this case P(b) and V(b) must alternate in their actions.P(b): < await (b > 0) b = 0; >V(b): < await (b < 1) b = 1; >
Critical Section - Semaphores Assume that there are n processes, each one containing a critical section .
Let: in[i] = 1 if process i is in CS and in[i]= 0 if process i is not in CS We want for the CS: (in[1]+…+in[n]<=1) to be a global invariant. Write S = 1 - (in[1] + in[2] ... + in[n]) Before process i enters the critical section we want: S = 1 (all in[i] to
be zero ) Inside the critical section we want: S = 0 (exactly one in[i] is one)
So we can protect a critical section by making:- Each entering process carry out a P(S) operation- Each exiting process carry out a V(S) operation
10
Semaphores
CS Solution Entry protocol is: < await (s 1) s = 0; > which is P(s), by definition. Exit protocol is: < s = s + 1; > which is V(s) by definition.
Define s : semaphore = 1 initially
Process P[i:1 to n]{ while (true){ P(s); …critical section V(s); } …non-critical section}
11
Semaphores Semaphore Applications
1. Producers and Consumers The mailbox in Toytown holds only one letter. Producers of messages put
letters into the mailbox, consumers take them out. A producer can put a letter into the mailbox if the mailbox is empty. A
consumer can take a letter out of the mailbox if the mailbox is full. A consumer must take any letter that is there.
Solution: Use two semaphores: empty and full.
Producers wait on empty, signal full. Consumers wait on full, signal empty.
The code is shown next:
MBuffer
P C
Process
Process
Empty Full(Semaphores)
12
SemaphoresMessage buf;sem empty := 1, sem full := 0
Process Producer[i: 1 to M] { while (true) { Message messi; { .. Produce value in messi..} P(empty);
buf := messi; V(full); } } Process Consumer[j:1 to N] { while (true){ Message messj; P(full); messj := buf; V(empty); { .. Consume value in messj .. } } }
Put letter into buffer
Take letter out of buffer
13
Semaphores
Split Binary Semaphores A set of binary semaphores b1, .., bn forms a split binary semaphore in a
program if the following assertion is a global invariant in the program:SPLIT: 0 b1 + b2 + .. bn 1 (empty = b1 and full = b2 form a split binary semaphore in the
producer/consumer program)
Bounded Buffer Problem Assume a mailbox has space for N messages. There is just one producer
and just one consumer. The aim is to add messages to the buffer if it is not full and remove messages from the buffer if it is not empty.
Producer: Add messages to buf[rear] and then increment rear. Consumer: Read messages from buf[front] and then increment front.
Note. Only empty or full is set to 1 at any time – i.e. mutual exclusion
14
Semaphores Let Empty and Full be semaphores that indicate the number of empty slots
and the number of full slots. Then Producer must wait on Empty, add the message and then
increment Full. Similarly Consumer must wait on Full, read the message and then
increment Empty.Message buf[1:n];sem Empty = N; sem Full = 0;int rear = 1; int front = 1;
Process Producer { Message messP; while (true) {
…create message m P(Empty); buf[rear] = messP; rear = rear mod N + 1; V(Full); }}
Process Consumer { Message messC; while (true) { P(Full); messC := buf[front]; front := front mod N + 1; V(Empty); }}
15
Semaphores Many Producers, Consumers
This is the bounded buffer problem, with the extra possibility that there can be many producers and many consumers. The producers all access the shared variable rear, and the consumers access the shared variable front.
Need to introduce two new semaphores: MutexP and MutexC to protect the critical sections in the code.
Message buf[1:n];sem Empty = N; sem Full = 0;int rear = 1; int front = 1;
sem MutexP = 1; sem MutexC = 1;
Global Variables (need to be protected by mutual exclusion)
16
SemaphoresProducer Producer { Message messP; while (true) { create message messP; P(Empty); P(MutexP); buf[rear] = messP; rear = rear mod N + 1; V(mutexP); V(Full); }}Process Consumer { Message messC; while (true) { P(Full); P(MutexC); messC = buf[front]; front = front mod N + 1; V(MutexC); V(Empty); }}
Only one Consumer process is allowed to access front of buffer value at any time
Only one Producer process is allowed to access rear of buffer at any time
Wait until there is space available in the buffer
Wait until there is at least one item in the buffer
Producer process gets mutually exclusive access to rear of buffer
Consumer process gets mutually exclusive access to front of buffer
Producer process releases exclusive access to rear of buffer
Consumer process releases exclusive access to front of buffer
Signal that an item has been placed in the buffer
Signal that there is another free space in the buffer
Semaphores Dining Philosophers
17
Philosophers Thinking/Eating Table Numbering
18
Semaphores The Dining Philosophers
The philosophers eat and think in a continuous cycle of activity. In order to eat a philosopher must acquire both a left fork and a right fork, although not necessarily in that order.
SolutionEach fork i is a shared resource and can be modelled by a binary semaphore fork[i].
sem fork[5] = {1, 1, 1, 1, 1}; (initially free)
Process Philosopher [i = 0 to 3]{//pick up left fork first while (true) { P(fork[i]); P(fork[i + 1]) …Eat V(fork[i]); V(fork[i + 1]) …Think }}
Wait for two forks to be available Release two forks
19
SemaphoresProcess Philosopher[4] {//pick up the right fork first while (true) P(fork[0]); P(fork[4]); …Eat V(fork[0]); V(fork[4]); …Think }} (Note. If they all pick up the left (or right) fork first then we will have deadllock!! )
The above program is deadlock-free. (Proof: Assume that Phil 4 is stuck. Then either he is waiting to get fork 0, or he is waiting to get fork 4 and so on ..).
Wait for two forks to be available
Release two forks
Assume you are waiting to get fork 0 Phil 0 is eating Phil 1 is NOT eating Phil 2 is eating Phil 3 is NOT eatingSo when Phil 0 stops eating then Phil 4 can start eating as fork 4 is free (Phil 3 is NOT eating) (Note. The same logic would apply going in an anticlockwise direction)
20
Semaphores The Readers and Writers
Any number of readers can access a DB, provided that there are no writers accessing the DB concurrently. Up to one writer can have exclusive access to the DB. (Database applications often have this situation with Locks).
Solution: Let nr be the number of readers. If no-one is writing then we can increase nr. If there is a writer, then everyone must wait until the writer which has
control of the resource has finished. Need one semaphore called Rw for condition synchronisation: Rw is 1
if no-one is accessing the DB, 0 otherwise. The second semaphore, MutexR, allows readers to access the global
variable nr in an orderly fashion.
DatabaseR
RR
W
21
SemaphoresProgram ReadersAndWriters {int nr = 0;sem MutexR = 1;sem Rw = 1;
Process Reader[i = 1 to m] { while (true) { P(MutexR); (wait to alter nr) nr = nr + 1; if (nr == 1) P(Rw); V(MutexR); …read DB P(MutexR); nr = nr - 1; if (nr == 0) V(Rw); V(MutexR); }}
Global Variable needs to be protected
First Reader waits for Writer to leave
Last Reader leaving signals waiting writer
Atomic update of global variable nr
Atomic update of global variable nr
22
Semaphores
(n writers - they must compete for writes)
Process Writer[j = 1 to n] while (true) { P(Rw); …write DB V(Rw); }}
} // end ReadersAndWriters
Wait until no Readers or a Writer is accessing the database
Signal a waiting Reader or Writer
23
Semaphores Barriers
Four workers work independently until they need to share results. A co-ordinator process waits until all four are finished. It reads the results produced by the workers and then issues fresh instructions to the workers, telling them to start again. Two semaphores: Done and Start_again
SomeDataStructure instruction[1:4];AnotherDataStructure result[1:4];sem Done = 0;sem StartAgain = 0;
Process Worker[i = 1 to 4] { while (true) { …work on local data result[i] = local data; V(Done); P(Start_again); …read instruction[i] -- from Co-ordinator }}
1234
WP1
WP1
WP1
WP1
CP
Results
V(Done)
V(Done)V(Done)V(Done) P(Done)
P(Done)P(Done)P(Done)
Note. The “reverse” pattern of signalling occurs on the semaphore StartAgain
Signal Result available Wait for next instruction
24
SemaphoresProcess Coordinator { while (true) { for [i = 1 to 4] P(Done); for [i = 1 to 4] …read result[i]; .. generate new instructions[1:4]
for [i = 1 to 4] V(Start_again); }}
Wait until all four processes have deposited results
Read Results and generate new instructions for workers
Signal all the workers to start again
25
Semaphores
Resource AllocationAssume we have a set of N processes which want a number of units of a
resource.Process Requester [i= 1to N] {<await (request satisfied) take u units>
…use the units return u units}
It may be desirable to examine the set of waiting processes explicitly and to grant the resource to selected processes.
26
Semaphores General Solution Pattern
1. Maintain a private working area of memory in which requests can be queued in a list, L, and the number of available units, U, can be stored.
2. Protect the area with a semaphore Mutex3. When requester makes request it reads U to see if the request can be
granted.(i) If grant can be made then allow the requester to proceed and
decrease U by u, the number of available units.(ii) Otherwise, there are not enough free units, so add the requester
identifier i to the queue, together with the size of the request, u and make the requester process wait on an appropriate semaphore b[i], from an array of sems.
4. On release: Increase the number of available units. Examine the request queue. If any requests can be granted then
decrease the number of available units and signal the appropriate semaphore b[i]. (b[1:N] is an array of binary semaphores, one for each process. Initially all b[i] are zero.)
27
Semaphoressem Mutex = 1;sem b[1:N] = ([N] 0) ; List L, const int U;…procedure Request(int i, int u) { P(Mutex); if (u < U) { U = U - u; V(Mutex); } else {…add Process i, and amount u to List V(Mutex); P(b[i]); }}procedure Release(int i, int u) P(Mutex); U = U + u; for each member, (i, uuu) of List { if (uuu < U) {//(…check U against (i, uuu)) U = U - uuu; …Remove (i, uuu) from List V(b[i]); } } V(Mutex);}
Result can be satisfied Get exclusive access
Release exclusive access
Release exclusive access Request cannot be satisfied so wait in queue
Get exclusive access Release the units back to the central resource
Check to see if requests waiting in queue can be satisfied
Signal process that has request satisfied that it can stop waiting
Release exclusive access
28
Semaphores Each process/program that wishes to use the resource (e.g. CPU time in a
time-slicing system) will call Requester and wait until it is granted the resource.
Process Requester[i = 1 to N] {
while (true) { compute u; # work out units needed Request(i, u); …use the units of the resource
Release(i, u); }}
Process to request resource
Process to release resource
29
Semaphores
Shortest Job Next - SJN A single resource is to be allocated to the waiting job (process) with the
shortest execution time. Examples include:
giving the CPU to the waiting process which will execute the most quickly,
giving a printer to the print job with the fewest pages
Let free be a boolean variable which is true when the resource is free, otherwise it is false. (var free = true (initially) )
Let L be a list of (time, proc_id) pairs where process proc_id has requested the resource for time (seconds).
Each process calls request() to get the resource and release() to release the resource.
Note. All the resource is held by a single process at a time
30
Semaphores SJN Semaphore Solutionsem e= 1; bsem b[1:n]=( [n]0 );List L; boolean free = true;
procedure request(time_taken, proc_id){ P(e);-- ensure exclusive if (not free) { …insert(time_taken, proc_id) in L (keeping list L in time order) V(e); P(b[proc_id]); }
free = false; -- got resource V(e);}
Add to list of waiting processes
Get exclusive access
Release exclusive access (without getting resource) Wait until signalled that the resource is available
Release exclusive access (after getting resource)
31
Semaphores
procedure release() { P(e); if (List L is non-empty){ … extract proc_id from head of list
V(b[proc_id]); } else free = true;
V(e);}
Get exclusive access
Release exclusive access
Signal waiting process at the head of the list
Indicate the resource is now free – it is handed back and there is nobody waiting to take it
32
Semaphores Question
Draw an Interaction Diagram for the Barrier Problem (Four Workers and one Coordinator).
Topics addressed: Problems with busy-waiting
Definition of a semaphore: init(s), P(s) and V(s) - invariant
Examples Critical Section Problem; Producers and Consumers Bounded Buffer; Dining Philosophers
Databases - Readers and Writers
Scheduling - barriers; SJN