51
Outline Monitors o Monitors in Java Barrier synchronization The sleeping barber problem Readers and Writers 1 Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Outline

  • Upload
    kairos

  • View
    41

  • Download
    0

Embed Size (px)

DESCRIPTION

Outline. Monitors Monitors in Java Barrier synchronization The sleeping barber problem Readers and Writers. Monitors - higher-level synchronization (Hoare, Hansen, 1974-5). Semaphores and event-counters are low-level and error-prone Monitors are a programming-language construct - PowerPoint PPT Presentation

Citation preview

Page 1: Outline

Outline

Monitorso Monitors in Java

Barrier synchronization

The sleeping barber problem

Readers and Writers

1Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Page 2: Outline

Monitors - higher-level synchronization(Hoare, Hansen, 1974-5)

Semaphores and event-counters are low-level and error-

prone

Monitors are a programming-language construct

Mutual exclusion constructs generated by the compiler.

Internal data structures are invisible.

Monitors combine 2 synchronization mechanisms:

o Only one process is active at any given time inside the monitor.

o Condition variables for signaling (wait / signal).

2Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Page 3: Outline

Monitors - DefinitionA monitor is a program module for concurrent

programmingo Encapsulate shared storage and operations.

A monitor has entry procedureso Entry procedures are called by processes (threads); the

monitor is passive.o The monitor guarantees mutual exclusion for calls of

entry procedures:Condition variables are defined in the monitor

o Condition Variables are used within entry procedures for condition synchronization.

3Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Page 4: Outline

4

MonitorsOnly one monitor procedure active at any given time

monitor exampleinteger i;condition c;

entry procedure p1( );...end;

entry procedure p2( );...end;end monitor;

Slide taken from a presentation by Gadi Taubenfeld from IDCBen-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Page 5: Outline

5

Monitors: Condition variables

Monitors guarantee “automatic” mutual exclusion

Conditional variables enable signaling.

Condition variables support two operations: waitwait and signalsignal

o Signaling has no effect if there are no waiting threadsSignaling has no effect if there are no waiting threads

The monitor provides queuing for waitingwaiting procedures

When one operation waitswaits and another signalssignals there are two ways to

proceed:

o The signaled operation will execute first: signaling operation immediately

followed by block()block() or exit_monitor exit_monitor ((HoareHoare semantics) semantics)

o The signaling operation is allowed to proceed (Java semantics)

Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Page 6: Outline

6

Monitors: Wait/Signalwait (c) The executing process leaves the monitor and waits in a set associated to

c, until it is released by a subsequent call signal(c); then the process accesses the monitor again and continues.

signal (c): The executing process releases one arbitrary process that waits for c.Which of the two processes immediately continues its execution in the monitor

depends on the variant of the signal semantics:

signal-and-exit semantics (Hoare’s semantics):The process that executes signal terminates the entry procedure call and leaves the monitor. The released process

enters the monitor immediately -without a state change in between and without the mutex being released ever (hand to hand transfer of the mutex from signaling process to waiting process).

signal-and-wait semantics: The process that executes signal leaves the monitor and waits to re-enter the monitor. The released process enters

the monitor immediately - without a state change in between (hand to hand transfer of mutex).signal-and-continue semantics (Java semantics):The process that executes signal continues execution in the monitor. The released process has to wait until the

monitor is free. The state that held at the signal call may be changed meanwhile; the waiting condition has to be checked again. (no hand to hand transfer of mutex.)

Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Page 7: Outline

7

type monitor-name = monitorvariable declarations

procedure entry P1 (…);begin … end;

procedure entry P2 (…);begin … end;

.

.

.procedure entry Pn (…);

begin … end;

begininitialization code

end

Figure 6.20 Monitor with Condition Variable

Shared dataxy

Queues associated with x, y conditions

…operations

Initialization code

Entry queue

Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Page 8: Outline

8

Bounded Buffer Producer/Consumer with Monitors

Slide taken from a presentation by Gadi Taubenfeld from IDC

This code only works if a signaled thread is the next to enter the monitor (Hoare)

Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Page 9: Outline

9

Issues if non-Hoare semantics

Slide taken from a presentation by Gadi Taubenfeld from IDC

1. The buffer is full, k producers (for some k>1) are waiting on the full condition variable. Now, N consumers enter the monitor one after the other, but only the first sends a signal (since count==N-1) holds for it. Therefore only a single producer is released and all others are not. The corresponding problem can occur on the empty semaphore.

Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Page 10: Outline

10

Issues if non-Hoare semantics (cont'd)

Slide taken from a presentation by Gadi Taubenfeld from IDC

2) The buffer is full, a single producer p1 sleeps on the full condition variable. A consumer executes and makes p1 ready but then another producer, p2, enters the monitor and fills the buffer. Now p1 continues its execution and adds another item to an already full buffer.

Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Page 11: Outline

MonitorsMonitors - some comments

Condition variables do not accumulate signals for later use

wait() must come before signal() in order to be signaled

No race conditions, because monitors have mutual exclusion

Complex to implement – but “difficult work” done by compiler

Implementation issues:

o How to interpret nested monitors?

o How to define wait, priority scheduling, timeouts, aborts?

o How to handle exception conditions?

o How to interact with process creation and destruction?

11Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Page 12: Outline

12

Implementing Monitors with Semaphores – take 1semaphore mutex=1; /*control access to monitor*/semaphore c /*represents condition variable c */

void enter_monitor() {down(mutex); /*only one-at-a-time*/

}void leave() {

up(mutex); /*allow other processes in*/}void leave_with_signal(semaphore c) { /* leave with signaling c*/

up(c); /*release the condition variable, mutex not released */}

void wait(semaphore c) { /* block on a condition c */ up(mutex); /*allow other processes*/ down (c); /*block on the condition variable*/}

Any problem with this code?

May deadlock.Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Page 13: Outline

13

Implementing Monitors with Semaphores – take 1semaphore mutex=1; /*control access to monitor*/semaphore c /*represents condition variable c */

void enter_monitor() {down(mutex); /*only one-at-a-time*/

}void leave() {

up(mutex); /*allow other processes in*/}void leave_with_signal(semaphore c) { /* leave with signaling c*/

up(c); /*release the condition variable, mutex not released */

}void wait(semaphore c) { /* block on a condition c */ up(mutex); /*allow other processes*/ down (c); /*block on the condition variable*/}

Hand to hand passing of mutex – but if “missed signal” (signal when no one waiting) – mutex is no freed deadlock.Solution is that signal must distinguish between signal->wait transitions and signal->exit transitions.

Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Signal as last call ina procedure – unblocksa process that did wait and leave the monitorwithout freeing mutex.

When wait resumesfrom down(c) it does notneed to acquire mutexbecause mutex was notfreed by signal(c)

Page 14: Outline

14

Implementing Monitors with Semaphores - CorrectImplementing Monitors with Semaphores - Correct

Semaphore mutex = 1; /* control access to monitor */Cond c; /* c = {count;semaphore} */void enter_monitor() {

down(mutex); /* only one-at-a-time */}void leave() {

up(mutex); /* allow other processes in */}void leave_with_signal(cond c) { /* cond c is a struct */

if (c.count == 0) up(mutex); /* no waiting, just leave.. */

else {c.count--;

up(c.s);}

}void wait(cond c) { /* block on a condition */

c.count++; /* count waiting processes */up(mutex); /* allow other processes */down(c.s); /* block on the condition */

}

Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Page 15: Outline

Outline

Monitorso Monitors in Java

Barrier synchronization

The sleeping barber problem

Readers and writers

15Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Page 16: Outline

Monitors in Java (before Java 5)

Java directly adapted the Monitor model with some changes.

Procedures designated as synchronized synchronized are like entry procedures.are like entry procedures.

o All Java Object instances include an implicit mutex lock.All Java Object instances include an implicit mutex lock.

No explicit condition variables

o Only a single implicit condition variable on “this”

o Signaling operations:

Wait()Wait()

Notify()Notify()

NotifyAll()NotifyAll()

16Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Page 17: Outline

Monitors in Java Util Concurrent

Explicit lock interface:Explicit lock interface:o Use when synchronized blocks don’t applyUse when synchronized blocks don’t apply

Time−outs, back−offsTime−outs, back−offs Assuring interruptibilityAssuring interruptibility Hand−over−hand lockingHand−over−hand locking Need multiple condition variables.Need multiple condition variables.

Multiple condition variables per lockMultiple condition variables per locko Condition interface with lock.newCondition()Condition interface with lock.newCondition()

17Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Page 18: Outline

Producer-consumer in JavaProducer-consumer in Javaclass BoundedBuffer { final Lock lock = new ReentrantLock(); final Condition notFull = lock.newCondition(); final Condition notEmpty = lock.newCondition(); final Object[] items = new Object[100]; int putptr, takeptr, count; public void put(Object x) throws InterruptedException { lock.lock(); try { while (count == items.length) notFull.await(); items[putptr] = x; if (++putptr == items.length) putptr = 0; ++count; notEmpty.signal(); } finally { lock.unlock(); } } public Object take() throws InterruptedException { lock.lock(); try { while (count == 0) notEmpty.await(); Object x = items[takeptr]; if (++takeptr == items.length) takeptr = 0; --count; notFull.signal(); return x; } finally { lock.unlock(); } }

}

18Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

The java.util.concurrent.ArrayBlockingQueue class provides this functionality (with generic types) so there is no reason to implement this class.

From :// . . / / / / / / / .http www docjar com docs api java util concurrent locks Condition htmlWritten by Doug Lea with assistance from members of JCP JSR-166

Java7 supports multiple condition variables on a single lock using the Lock interfaceand the newCondition() factory.

Observe the pattern:

lock.lock();try {…} finally { lock.unlock();}

to enforce mutex using an explicit lock(instead of the implicit synchronized).Explicit locks support testing for locking and timeout.

condition.await() and signal()require that the underlying lock be acquired – else throw IllegalMonitorState.

Page 19: Outline

Producer-consumer in JavaProducer-consumer in Javaclass Producer implements Runnable { private BoundedBuffer bb; public Producer(BoundedBuffer b) {bb = b;} void run() { while(true) { Integer item = produceItem(); bb.insert(item); } } protected Integer produceItem() { …}}

class Consumer implements Runnable { private BoundedBuffer bb; public Consumer(BoundedBuffer b) {bb = b;} void run() { while(true) { int item = bb.extract(); consume(item); } } protected void consume(Integer item) { …}}

19Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

class ProducerConsumer { private Producer p; private Consumer c; private BoundedBuffer b;

public ProducerConsumer() { b = new BoundedBuffer(); p = new Producer(b); c = new Producer(b); }

public static int main(String args[]){ (new Thread(p)).start(); (new Thread(c)).start(); }

}

Page 20: Outline

Monitors in Java: commentsMonitors in Java: comments notify() does not have to be the last statement

wait() adds the calling Thread to the queue of waiting threads

a Thread performing notify() is not blocked - just moves one waiting Thread to

state ready

once the monitor is open, all queued ready Threads (including former waiting

ones) are contesting for entry (NO hand to hand passing of mutex).

To ensure correctness, wait() operations must be part of a condition-checking

loop (because of the “hole” in the mutex between notify() and resume of

wait()).

20Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Page 21: Outline

Outline

Monitorso Monitors in Java

Barrier synchronization

The sleeping barber problem

Readers and writers

21Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Page 22: Outline

Barriers

Useful for computations that proceed in phases Use of a barrier:

(a) processes approaching a barrier(b) all processes but one blocked at barrier(c) last process arrives, all are let through

22Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Page 23: Outline

23

Using CyclicBarrier in Javaimport java.util.concurrent.BrokenBarrierException;import java.util.concurrent.CyclicBarrier;import java.util.logging.Level;import java.util.logging.Logger;

public class CyclicBarrierExample {    //Runnable task for each thread    private static class Task implements Runnable {        private CyclicBarrier barrier;        public Task(CyclicBarrier barrier) {            this.barrier = barrier;        }

        public void run() {            try {                System.out.println(Thread.currentThread().getName() + " is waiting on barrier");                barrier.await();                System.out.println(Thread.currentThread().getName() + " has crossed the barrier");            } catch (InterruptedException ex) {                Logger.getLogger(CyclicBarrierExample.class.getName()).log(Level.SEVERE, null, ex);            } catch (BrokenBarrierException ex) {                Logger.getLogger(CyclicBarrierExample.class.getName()).log(Level.SEVERE, null, ex);            }        }    }

Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Page 24: Outline

24

public static void main(String args[]) {        //create a CyclicBarrier with 3 parties, i.e., 3 Threads needs to call await()        final CyclicBarrier cb = new CyclicBarrier(3, new Runnable() {            public void run(){                //This task will be executed once all threads reach barrier                System.out.println("All parties are arrived at barrier, lets play");            }        });        new Thread(new Task(cb), "Thread 1").start();        new Thread(new Task(cb), "Thread 2") .start();        new Thread(new Task(cb), "Thread 3") .start();    }}

Output:Thread 1 is waiting on barrierThread 3 is waiting on barrierThread 2 is waiting on barrierAll parties are arrived at barrier, lets playThread 3 has crossed the barrierThread 1 has crossed the barrierThread 2 has crossed the barrier

Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Using CyclicBarrier in Java

Page 25: Outline

25

//Dispatch work to N workers //Then merge the results.

class Solver{ final int N;

final float[][] data; final CyclicBarrier barrier;

class Worker implements Runnable{

int myRow; Worker(int row) { myRow = row; }

public void run{ )( while (!done()){

processRow(myRow); try{

barrier.await ;)( } catch (InterruptedException ex) {

return ; } catch (BrokenBarrierException ex) {

return ;} } } }

Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

public Solver(float[][] matrix){ data = matrix;

N = matrix.length; barrier = new CyclicBarrier(N ,

new Runnable{ )( public void run { )( mergeRows;)...(

} ;)}

for (int i = 0; i < N; ++i) new Thread(new Worker(i)).start;)(

waitUntilDone;)(} {

Read more on the - Fork Join Framework://http . . . / / / .gee cs oswego edu dl cpjslides fj pdf

Typical Use of CyclicBarrierFork and Join

Page 26: Outline

Fetch-and-increment(w)do atomically prev:=w w:=w+1 return prev

Implementing CyclicBarrierThe fetch-and-increment instruction

26Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Called InterlockedIncrement in Windows

Page 27: Outline

27

Why can’t we just do simple?

shared integer counter=0Barrier()

Fetch-and-increment(counter)await (counter == n)

We want to reset the barrier and re-use it (recycle) andWe want to execute a follow-up action only once.

Who should reset? Beware the race condition!

Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Page 28: Outline

28

A simple barrier using fetch-and-inc

shared integer counter=0, bit golocal local-go, local-counterBarrier() local-go := go local-counter := Fetch-and-increment(counter) if (local-counter == n-1) counter := 0 go := 1-go else await (local-go ≠ go)

Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

This is a busy-wait solution – look at Java solution for lock-basedhigher latency barrier: http://www.docjar.com/html/api/java/util/concurrent/CyclicBarrier.java.html

Page 29: Outline

Outline

Monitorso Monitors in Java

Barrier synchronization

The sleeping barber problem

Readers and writers

29Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Page 30: Outline

public class CyclicBarrier { /** * Each use of the barrier is represented as a generation instance. * The generation changes whenever the barrier is tripped, or * is reset. There can be many generations associated with threads * using the barrier - due to the non-deterministic way the lock * may be allocated to waiting threads - but only one of these * can be active at a time (the one to which <tt>count</tt> applies) * and all the rest are either broken or tripped. * There need not be an active generation if there has been a break * but no subsequent reset. */ private static class Generation { boolean broken = false; }

/** The lock for guarding barrier entry */ private final ReentrantLock lock = new ReentrantLock(); /** Condition to wait on until tripped */ private final Condition trip = lock.newCondition(); /** The number of parties */ private final int parties; /* The command to run when tripped */ private final Runnable barrierCommand; /** The current generation */ private Generation generation = new Generation();

/** * Number of parties still waiting. Counts down from parties to 0 * on each generation. It is reset to parties on each new * generation or when broken. */ private int count;

CyclicBarrier Java Implementation (1/4)CyclicBarrier Java Implementation (1/4)

30Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Page 31: Outline

/** * Updates state on barrier trip and wakes up everyone. * Called only while holding lock. */ private void nextGeneration() { // signal completion of last generation trip.signalAll(); // set up next generation count = parties; generation = new Generation(); }

/** * Sets current barrier generation as broken and wakes up everyone. * Called only while holding lock. */ private void breakBarrier() { generation.broken = true; count = parties; trip.signalAll(); }

public CyclicBarrier(int parties, Runnable barrierAction) { if (parties <= 0) throw new IllegalArgumentException(); this.parties = parties; this.count = parties; this.barrierCommand = barrierAction; }

public int await() throws InterruptedException, BrokenBarrierException { try { return dowait(false, 0L); } catch (TimeoutException toe) { throw new Error(toe); // cannot happen; } }

CyclicBarrier Java Implementation (2/4)CyclicBarrier Java Implementation (2/4)

31Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Page 32: Outline

/** * Main barrier code, covering the various policies. */ private int dowait(boolean timed, long nanos) throws InterruptedException, BrokenBarrierException, TimeoutException { final ReentrantLock lock = this.lock; lock.lock(); try { final Generation g = generation;

if (g.broken) throw new BrokenBarrierException();

if (Thread.interrupted()) { breakBarrier(); throw new InterruptedException(); }

int index = --count; if (index == 0) { // tripped boolean ranAction = false; try { final Runnable command = barrierCommand; if (command != null) command.run(); ranAction = true; nextGeneration(); return 0; } finally { if (!ranAction) breakBarrier(); } }

CyclicBarrier Java Implementation (3/4)CyclicBarrier Java Implementation (3/4)

32Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Page 33: Outline

// loop until tripped, broken, interrupted, or timed out for (;;) { try { if (!timed) trip.await(); else if (nanos > 0L) nanos = trip.awaitNanos(nanos); } catch (InterruptedException ie) { if (g == generation && ! g.broken) { breakBarrier(); throw ie; } else { // We're about to finish waiting even if we had not // been interrupted, so this interrupt is deemed to // "belong" to subsequent execution. Thread.currentThread().interrupt(); } }

if (g.broken) throw new BrokenBarrierException();

if (g != generation) return index;

if (timed && nanos <= 0L) { breakBarrier(); throw new TimeoutException(); } } } finally { lock.unlock(); } }

CyclicBarrier Java Implementation (4/4)CyclicBarrier Java Implementation (4/4)

33Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Page 34: Outline

What makes the code complex?- Interruptibility: what happens if any thread that is waiting on

barrier is interrupted?- Exceptions: what happens if the thread that executes the followup

action throws an exception?- Timeouts: how can we wait for the barrier for a limited amount of

time and give up after timeout?

That is – Barrier can exit for 4 different reasons: (1) tripped (good), (2) broken, (3) interrupted or (4) timed out.

Introduce “broken barrier” case and “Generation” object:- Can break barrier from the outside to “free” the blocked threads.- Barrier is broken in case of interruption- Threads of different generations can co-exist

CyclicBarrier Java Implementation: NotesCyclicBarrier Java Implementation: Notes

34Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Page 35: Outline

35

The Sleeping Barber ProblemThe Sleeping Barber Problem

Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Page 36: Outline

The sleeping barber problem (cont’d)The sleeping barber problem (cont’d)

Barber shopBarber shop - oneone service provider; many customers

A finite waiting queue

One customer is served at a time

Service provider, barberbarber, sleeps when no customers are waiting

Customer leavesleaves if shop is full

Customer sleepssleeps while waiting in queue

36Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Page 37: Outline

#define CHAIRS 5Semaphore customers = 0; // number of waiting customersSemaphore barbers = 0; // number of available barbers: either 0

or 1int waiting = 0; // copy of customers for reading Semaphore mutex = 1; // mutex for accessing ‘waiting’

void barber() {while (TRUE) { down(customers); // block if no customers down(mutex); // access to ‘waiting’ waiting = waiting - 1; up(barbers); // barber is in. up(mutex); // release ‘waiting’

// Synchronization complete: // One barber faces one customer.

cut_hair(); }}

The sleeping barber: implementationThe sleeping barber: implementation

37Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Page 38: Outline

The sleeping barber: implementation (cont’d)The sleeping barber: implementation (cont’d)

void customer() {

down(mutex); // access to `waiting’ if (waiting < CHAIRS) {

waiting = waiting + 1;

up(customers); // wake up barber

up(mutex); // release ‘waiting’

down(barbers); // go to sleep if barbers=0

// Synchronization complete:

// one customer, one barberget_haircut();

} else {up(mutex); // shop full - leave

}

}

38

Any problem with this code?

Two customers on chair at once

Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Page 39: Outline

39

The sleeping barber: The sleeping barber: correct synchronizationcorrect synchronization

#define CHAIRS 5Semaphore customers = 0; // number of waiting customersSemaphore barbers = 0; // number of available barbers: 0 or 1Semaphore mutex = 1; // mutex for accessing ‘waiting’Semaphore synch = 0; Semaphore synch = 0; // synchronize the service operation// synchronize the service operationint waiting = 0; // copy of customers for reading

void barber() { while (TRUE) {

down(customers); // block if no customers down(mutex); // access to ‘waiting’ waiting = waiting - 1; up(barbers); // barber is in.. up(mutex); // release ‘waiting’ cut_hair(); down(synch)down(synch) //wait for customer to leave //wait for customer to leave

}}

Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Page 40: Outline

40

The sleeping barberThe sleeping barber: : correct synchronization correct synchronization (cont’d)(cont’d)

void customer() {

down(mutex); // access to `waiting’ if (waiting < CHAIRS) { waiting = waiting + 1; up(customers); // wake up barber up(mutex); // release ‘waiting’ down(barbers); // go to sleep if barbers=0 get_haircut();

up(sync); up(sync); // synchronize service// synchronize service

// customer leaves chair// customer leaves chair} else { up(mutex); // shop full .. leave}

}

Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Page 41: Outline

41

The sleeping barberThe sleeping barber inin Java - BarberJava - Barberpublic class Barber implements Runnable {

private Queue<Customer> customers; private Shop shop; public Barber(Shop shop) {

this.shop = shop; customers = new LinkedBlockingQueue<Customer>(3);

} public void addCustomerToQueue(Customer customer) { customers.add(customer);} public void run() {

while (! customers.isEmpty()) { Customer customer = customers.remove();performHaircut(customer); shop.releaseChair();

} } private void performHaircut(Customer customer) {

System.out.println("Customer " + customer.getId() + " has got a haircut");

}

}

Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

:// . / /2013/03/18/ - - - - - - - /http bluepi in blogs actors in action sleeping barber problem with akka

Page 42: Outline

42

The sleeping barberThe sleeping barber inin Java - ShopJava - Shoppublic class Shop {

private Barber barber; private Semaphore semaphore; private AtomicInteger count = new AtomicInteger(0); // customers served public Shop() { semaphore = new Semaphore(3); // How many chairs in shop } public void init() { barber = new Barber(this); Executors.newSingleThreadScheduledExecutor() .scheduleAtFixedRate(barber, 100, 1000, TimeUnit.MILLISECONDS); }public void acquireChair(Customer customer) throws InterruptedException { boolean acquired = semaphore.tryAcquire(1, 100, TimeUnit.MILLISECONDS); if (acquired) { count.getAndIncrement(); barber.addCustomerToQueue(customer); } else { System.out.println("Turning customer " + customer.getId() + " away"); } } public void releaseChair() { semaphore.release(1); } public int getSuccessfulHaircutCount() { return count.intValue(); }

}

Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Page 43: Outline

43

The sleeping barberThe sleeping barber inin Java - NotesJava - Notes1. Barber is an active object (Runnable) which works in the context of a Shop. Shop activates Barber

in an executor.

2. Shop at the time of initialization passes itself as a callback to the Barber so that all the activities performed by Barber can be recorded by the shop.

3. Shop in the init method starts the barber in a periodic executor to periodically invoke run method. This is instead of the “while (true)” loop of the naïve code (reduces contention on the blockingQueue when many customers arrive at once).

4. When a customer arrives, it tries to acquire a chair which is represented by a Semaphore(N), N is the number of spots in the waiting room of the shop. No more than N customers can wait at any given point. Note how we use the “tryAcquire” method of the semaphore with timeout instead of testing explicitly for a counter as in the naïve code.

5. Note usage of AtomicInteger to safely count served customers.

Questions:

1. Complete code that simulates arrival of Customers.

2. Why is init() needed in Shop? (Review “Escape reference” problem from SPL)

3. Is the Barber queue used in a safe manner? (Any possible conflict between thread inserting new Customers in addCustomerToQueue() and Barber taking them in run()?)

4. Write a simpler version exploiting the BlockingQueue synchronization capabilities – compare performance.

5. How does the size of the waiting room impact overall performance?

Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Page 44: Outline

Outline

Monitorso Monitors in Java

Barrier synchronization

The sleeping barber problem

Readers and writers

44Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Page 45: Outline

The readers and writers problemThe readers and writers problem

Motivation: database access

Two groups of processes: readers, writers

Multiple readers may access database simultaneously

(no conflicts on read-only)

A writing process needs exclusive database access

45Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Page 46: Outline

Readers and Writers: 1st algorithmReaders and Writers: 1st algorithm

void reader() { while (TRUE) { down(mutex); rc = rc + 1; if (rc == 1) down(db); up(mutex); read_data_base(); down(mutex); rc = rc - 1; if (rc == 0) up(db); up(mutex); }}

Int rc = 0 // # of reading processessemaphore mutex = 1; // controls access to rcsemaphore db = 1; // controls database access

void writer() { while(TRUE) { down(db); write_data_base() up(db)}

Who is more likely to run: readers or

writers?

46Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Page 47: Outline

Comments on 1st algorithm

No reader is kept waitingNo reader is kept waiting, unless a writer has already

obtained the db semaphore

Writerriter processes may starveprocesses may starve - if readers keep coming

in and hold the semaphore db

An alternative version of the readers-writers problem

requires that no writer is kept waiting once it is no writer is kept waiting once it is

“ready”“ready” - when a writer is waiting, no new reader can

start reading

47Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Page 48: Outline

Readers and Writers: Writers priority

void reader() { while(TRUE) { down(Rdb); down(Rmutex); rc = rc + 1; if(rc == 1) down(Wdb); up(Rmutex); up(Rdb) read_data_base(); down(Rmutex); rc = rc - 1; if (rc == 0) up(Wdb); up(Rmutex); }}

Int rc, wc = 0 // # of reading/writing processessemaphore Rmutex, Wmutex = 1; // controls readers/writers access to rc/wcsemaphore Rdb, Wdb = 1; // controls readers/writers database access

void writer() { while(TRUE) { down(Wmutex); wc = wc + 1; if (wc == 1) down (Rdb); up(Wmutex); down(Wdb); write_data_base(); up(Wdb); down(Wmutex); wc = wc-1; if (wc == 0) up(Rdb); up(Wmutex); }}

48Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Page 49: Outline

Comments on 2nd algorithm

When Readers are holding WdbWhen Readers are holding Wdb, the first Writerriter to arrive

decreases RdbRdb

All ReadersAll Readers arriving later are blocked on RdbRdb

All Writersriters arriving later are blocked on WdbWdb

Only the last Writerriter to leave WdbWdb releases RdbRdb – Readers can

wait…

If a writerwriter and a few readersreaders are waiting on RdbRdb, the writerwriter may

still have to wait for these readersreaders. If RdbRdb is unfair, the writerwriter may

again starve.

49Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Page 50: Outline

Readers and Writers: improved writers priority

void reader() { while(TRUE) { down(Mutex2) down(Rdb); down(Rmutex); rc = rc + 1; if (rc == 1) down(Wdb); up(Rmutex); up(Rdb) up(Mutex2) read_data_base(); down(Rmutex); rc = rc - 1; if(rc == 0) up(Wdb); up(Rmutex); }}

Int rc, wc = 0 // # of reading/writing processessemaphore Rmutex, Wmutex, Mutex2 = 1; semaphore Rdb, Wdb = 1;

void writer() { while(TRUE) { down(Wmutex); wc = wc + 1 if (wc == 1) down (Rdb); up(Wmutex); down(Wdb); write_data_base(); up(Wdb); down(Wmutex); wc = wc-1; if (wc == 0) up(Rdb); up(Wmutex); }}

50Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels

Page 51: Outline

Improved writers priority

After the first writer does down(Rdb), down(Rdb), the first reader that enters

is blocked after doing down(Mutex2)down(Mutex2) and before doing up(Mutex2)up(Mutex2). Thus

no other readers can block on RdbRdb.

This guarantees that the writer has to wait for at most a single reader.

51Ben-Gurion University Operating Systems, 2013, Meni Adler, Michael Elhadad, Amnon Meisels