semaphores - appalachian state university€¦ · semaphores • semaphores are a convenient...
TRANSCRIPT
Semaphores• Semaphores are a convenient mechanism to
not only solve the mutex problem but to also synchronize the activities of multiple threads
• Semaphores were devised by Edsgar Djikstra p y g jin the 1960s when working on a multithreaded operating systemp g y
• We will use semaphores to solve four classic concurrency problems: producers andconcurrency problems: producers and consumers using a bounded buffer, dining philosophers the sleeping barber and thephilosophers, the sleeping barber, and the readers-writers in a database
The Binary Semaphore• A binary semaphore has the following
characteristics– It only has two values, 0 (meaning the resource is
in use) and 1 (meaning the resource is available)– It is initialized to 1 and can only be changed by the
operations P (from the Dutch passeren meaning t ) d V (f th D t h ito pass) and V (from the Dutch vrygeven meaning to release)J h th th d i– Java semaphores use the methods acquire (operates like P) and release (operates like V)
The P and V Operations• Every semaphore has a waiting queue associated with
the semaphore; this queue is initially empty• Both P and V operate atomically and have the• Both P and V operate atomically and have the
following behavior expressed in pseudocode:P(Semaphore s) V(Semaphore s)
wait until s = 1 if queue is not emptys = s-1 wake up a task on queue
end P else s = 1end Vend V
• There is no implied order in waking up a waiting task but if the queue is a strict FIFO queue thentask but if the queue is a strict FIFO queue then the task waiting longest is woken up
• If it is a priority queue then the task with theIf it is a priority queue then the task with the highest priority is woken up
Solving the Mutex Problem• We assume a shared memory machine where
the binary semaphore has been initialized to 1• Before a critical region each thread calls the P
operation to request entry and then calls the V p q yoperation to release the critical resource
• In pseudocode Using Java syntaxIn pseudocode Using Java syntaxP(S) S.acquire() critical region critical regioncritical region critical regionV(S) S.release()
• This insures only one thread is in the critical• This insures only one thread is in the critical region at a time
Implementing Semaphores in Java• Semaphores are normally implemented at the
operating system level; here we describe a high level solution in Java
• It is based on a busy-wait, which, of course, is y , , ,inefficient
• In your programs you will use the SemaphoreIn your programs you will use the Semaphore class available as a Java API
Busy-Wait Implementationclass Semaphore {
private int value;public Semaphore() { value = 0; }public Semaphore(int val) { value = val; }public Semaphore(int val) { value val; }public void P() {wantToEnterCritical(); // need a parameter??? while(value == 0) {
fi i h dI C iti l()finishedInCritical(); wantToEnterCritical();
}value--;;finishedInCritical();
}public void V() {wantToEnterCritical(); value++;
finishedInCritical(); }}
}
The Semaphore Class - 1• The semaphore class was added to Java with
version 1.5• Using this class avoids wasteful busy-wait
loops as shown previouslyp p y
Constructor SummarySemaphore(int permits)
Creates a Semaphore with the given number of permits and nonfair fairness setting.
Semaphore(int permits, boolean fair)Creates a Semaphore with the given number of permits and the given fairness setting.
The Semaphore Class - 2Method Summary
void acquire()Acquires a permit from this semaphore, blocking until one is available, or the
thread is interrupted.
void acquire(int permits)Acquires the given number of permits from this semaphore, blocking until all
are available, or the thread is interrupted.
void acquireUninterruptibly()q p y()Acquires a permit from this semaphore, blocking until one is available.
void acquireUninterruptibly(int permits)Acquires the given number of permits from this semaphore, blocking until all
are available.
int availablePermits()Returns the current number of permits available in this semaphore.
int drainPermits()Acquires and returns all permits that are immediately available.Acquires and returns all permits that are immediately available.
protected Collection<Thread>
getQueuedThreads()Returns a collection containing threads that may be waiting to acquire.
int getQueueLength()Returns an estimate of the number of threads waiting to acquireReturns an estimate of the number of threads waiting to acquire.
boolean hasQueuedThreads()Queries whether any threads are waiting to acquire.
The Semaphore Class - 3boolean isFair()
Returns true if this semaphore has fairness set true.
protected void reducePermits(int reduction)Shrinks the number of available permits by the indicated reduction.
void release()Releases a permit, returning it to the semaphore.
void release(int permits)Releases the given number of permits, returning them to the semaphore.
String toString()Returns a string identifying this semaphore, as well as its state.
boolean tryAcquire()Acquires a permit from this semaphore only if one is available at the time ofAcquires a permit from this semaphore, only if one is available at the time of
invocation.
boolean tryAcquire(int permits)Acquires the given number of permits from this semaphore, only if all are
available at the time of invocation.
boolean tryAcquire(int permits, long timeout, TimeUnit unit)Acquires the given number of permits from this semaphore, if all become
available within the given waiting time and the current thread has not been interrupted.
boolean tryAcquire(long timeout TimeUnit unit)boolean tryAcquire(long timeout, TimeUnit unit)Acquires a permit from this semaphore, if one becomes available within the
given waiting time and the current thread has not been interrupted.
The Dining Philosophers• Philosophers live a boring life; they think; eat;
think; eat; and continue this cycle for their entire lives
• Philosophers have assigned places around p g pthe dining table; they are health nuts so they only eat salad which is placed in the centery p
• Each philosopher has a possible chopstick to his/her right and another chopstick to his/herhis/her right and another chopstick to his/her left; it takes two chopsticks to eat and they can only use their assigned two chopsticksonly use their assigned two chopsticks
• Chopsticks cannot be shared simultaneously
The Dining Philosopher• The dining table with five philosophers
0
l d
4 1salad
3 2
A First Attempt at a Solution• Suppose the chopsticks have the following
ids: the chopstick to the right of philosopher j is labeled j; the chopstick to the left is labeled j+1 mod n (in our problem n = 5)
• Each philosopher j follows this routine after entering and sitting at the table: pick up the g g p pchopstick on the right; pickup the chopstick on the left; eat some salad; put down the ; ; pchopstick on the right; put down the chopstick on the left; leave the dining room to go think; g g
• Are their any problems with this algorithm?
In-Class Lab Activity• Test the given code of picking up first the right
chopstick and then the left chopstick for possible deadlock
• Make deadlock more likely by introducing a y y gdelay between picking up the two chopsticks
• This lab activity is described in more detail onThis lab activity is described in more detail on a separate lab sheet
Problem and Possible Solution• Problem: deadlock may occur if
simultaneously each philosopher picks up his/her right chopstick but cannot pick up the left chopstick (it is being held by the philosopher to the left)
• Possible Solution: only pick up two y p pchopsticks at the same time and put down two chopsticks at the same time; wait patiently p ; p yuntil both chopsticks are available since each philosopher eventually stops eatingp p y p g
• Is there a problem with this solution?
The Starving Philosopher• It is possible for the philosophers on each side
of a particular philosopher to starve their colleague; suppose philosopher 2 wants to eat
• P1 is eating so P2 waits for both chopsticksg p• P1 only puts down his/her chopsticks after P3
starts eating; P2 cannot get both chopsticksstarts eating; P2 cannot get both chopsticks• P3 only puts down his/her chopsticks after P1
comes back to the dining room and startscomes back to the dining room and starts eating; P2 cannot get both chopsticksP1 d P3 ti thi b h i lit ll• P1 and P3 continue this behavior literally starving P2 to death
Another Way to Prevent Deadlock• There are several ways to prevent deadlock,
some solutions involve picking up chopsticks one at a time, but having some philosophers pick up the right chopstick first and others pick up the left chopstick first
• We will introduce an even simpler solution by p ylimiting the number of philosophers in the dining room to n-1 at a timeg
• We need to introduce a general counting semaphore to implement this solutionsemaphore to implement this solution
A General Counting Semaphore• The semaphore is initialized to some value n
that is greater than 0; this means that n tasks can access the critical resource at a time
• The semaphore value can only be changed by p y g ythe atomic operations P and VP(Semaphore s) V(Semaphore s)
wait until s > 0 if queue is not emptywait until s > 0 if queue is not emptys = s-1 wake up a task on queue
end P else s = s + 1end Vend V
Limiting Access to the Dining Room• A simple solution to the possible starvation
problem with the dining philosophers is to limited access to the dining room to n-1 philosophers
• Suppose the semaphore diningroom has been initialized to n-1 then the eat task would be:
eat(int philosopherID)P(diningroom)P(diningroom)// code for getting chopsticks and eatingV(diningroom)
end eatend eat
In-Class Lab Activity• Introduce a counting semaphore into your
dining philosopher program• Verify that limited the number of philosophers
in the room to n-1 breaks the deadlock caused by the delays you introduced in the prior lab
• Verify that if n philosophers are allowed in theVerify that if n philosophers are allowed in the room then the deadlock reappears
• This lab activity is described in more detail on• This lab activity is described in more detail on a separate lab sheet
The Producer-Consumer Problem• Producers generate data and consumers fetch
and use data; these processes often occur at different rates so the data is buffered
P1
P2
C1
C2P2
P3
C2
C3BOUNDED BUFFER
Pm Cn
The Need for a Semaphore• Two conditions must be blocked: any producer
trying to put something in a full buffer and any consumer trying to fetch from an empty buffer
• The spaces semaphore counts the number of p pempty spaces and is initialized to the buffer size; the elements semaphore counts the ; pnumber of items in the buffer; it is intialized to 0deposit(item) fetch()P(spaces) P(elements)add item to buffer get item from bufferV(elements) V(spaces)
end deposit return itemend fetch
Expanded Solution• Semaphores• Semaphores
– spaces is a counting semaphore for the number of empty slots in the buffer; initialized to numSlotsp y ;
– elements is a counting semaphore for the number of items in the buffer; initialized to zero
– mutex is a binary semaphore that protects updates to the shared variable count
Th d it d f t h th d• The deposit and fetch methodsdeposit(value) fetch()P(spaces) P(elements)P( t ) P( t )P(mutex) P(mutex)add value to buffer remove item from bufferincrement count decrement countV(mutex) V(mutex)V(elements) V(spaces)
end deposit return itemend fetch
Problems with Semaphores• Many problem solutions require multiple
semaphores; if the order of the P and V ti i h d th l ti toperations is changed, the solution may not
workE l• Example:deposit(value) fetch()P(spaces) P(mutex)P(mutex) P(elements)P(mutex) P(elements)add value to buffer remove value from bufferincrement count decrement countV(mutex) V(mutex)V(elements) V(spaces)
end deposit return valueend fetch
C h ?• Can you spot the error?
The Sleeping Barber ProblemTh b b h h i i h i l• The barber shop has a cutting room with a single barber and one barber chairTh i iti ith fi d b f h i• There is a waiting room with a fixed number of chairs for customers to waitIf a customer arrives and the waiting room is full; the• If a customer arrives and the waiting room is full; the customer leaves and comes back later
• When the barber finishes with the current customer he• When the barber finishes with the current customer he gets the next customer from the waiting room or takes a nap in the barber chair if no customers are waitinga nap in the barber chair if no customers are waiting
• If the waiting room is empty when a customer arrives and the barber is napping, the customer wakes the pp g,barber and then gets into the barber chair (after the barber gets out!)
The Barber Shop
The semaphores and variables• waiting is an integer variable that counts the number of
waiting customers; it is initialized to zero• mutex is a binary semaphore protecting changes in the• mutex is a binary semaphore protecting changes in the
variable waiting• customers is a counting semaphore that is initialized to zero;
it will be incremented by the V operation every time there is room for the customer in the waiting room
• cutting is a counting semaphore initialized to zero; the barber• cutting is a counting semaphore initialized to zero; the barber waits on the semaphore cutting, the customer signals the barber to start cutting after getting into the chair
• barber is a counting semaphore that is initialized to zero; when signaled by the barber it allows the next customer to get into the barber chair for a haircut; the customer blocks on thisinto the barber chair for a haircut; the customer blocks on this semaphore until signaled by the barber
Barber’s wantToCut method• PseudocodewantToCut
P(customers) // wait for customerP(customers) // wait for customerP(mutex)decrement waitingV(barber)V(mutex)P(cutting) // cut the hair( g) //
end wantToCut
Customer’s wantHairCut method• PseudocodewantHairCut(int i)
P(mutex) // check waiting roomP(mutex) // check waiting roomif(waiting < numChairs)increment waitingV(customers) // take a seatV(customers) // take a seatV(mutex)P(barber) // wait for barberV(cutting) // get haircutV(cutting) // get haircut
elseV(mutex)
end ifend wantHairCut
In-Class Lab Activity• You are given a complete program for the
sleeping barber problem, however the code for the methods wantToCut and wantHaircut is missing
• Complete these methods in accordance with the pseudocode on the previous slidesp p
• This lab activity is described in more detail on a separate lab sheeta separate lab sheet
Multiple Sleeping Barbers• It is possible to extend the sleeping barbers to
have multiple barbers, each with his own room and chair, but all sharing the same waiting room
• Call the number of chairs in the waiting room n, the number of customers m, and the , ,number of barbers k
• To make this realistic you should set theTo make this realistic, you should set the number of customers m to a value greater than the total number of chairs n+k for waitingthan the total number of chairs, n+k for waiting room chairs and barber chairs
The Readers-Writers Problem• It is assumed the write operation changes the
underlying data structure, so it must be done atomically, but the read operation does not change the data structure, so multiple reads can be done simultaneously
• To enforce mutual exclusion for both reads and writes would work but not be efficient since simultaneous reads are possible without pdanger
• What are your ideas on how to solve thisWhat are your ideas on how to solve this problem efficiently?
A First Solution - 1• There will be an integer count of the currentThere will be an integer count of the current
number of readers; it is initialized to zero• There will be two binary semaphores, we callThere will be two binary semaphores, we call
one mutex and it will protect changes to the count of the number of readers
• the other semaphore will be called ok; it will ensure that nothing else accesses the data during the write operation
• Readers will use the following methods:startRead(int i) endRead(int i)P(mutex) P(mutex)increment numReaders decrement numReadersif(numReaders == 1) P(ok) if(numReaders == 0) V(ok)if(numReaders 1) P(ok) if(numReaders 0) V(ok)V(mutex) V(mutex)
end startRead end endRead
A First Solution - 2• Writers will use the following methods:
startWrite(int i) endWrite(int i)P(ok) V(ok)
end startWrite end endWrite
• Carefully explain when and where a reader waits on a semaphore (hint: readers can wait on either mutex or ok, so distinguish these situations)
• There is a serious shortcoming to this first gsolution; can you spot what it is?
• During the after-class lab activity you willDuring the after class lab activity you will attempt to fix this problem
After-Class Lab Activity• If there are multiple readers and only one
writer, it is possible the writer can be starved• You are given a complete program that
demonstrates this behavior• Try to avoid this starvation by not allowing any
new readers once a writer appearsnew readers once a writer appears• This lab activity is described in more detail on
a separate lab sheeta separate lab sheet