Simple synchronization problems q Monitors o Monitors in
Simple synchronization problems q Monitors o Monitors in Java q Barrier synchronization q The sleeping barber problem q Readers and Writers q One-way tunnel Operating Systems, 2011, Danny Hendler & Amnon Meisels 1
Monitors - higher-level synchronization q Semaphores and event-counters are low-level and error-prone q Monitors are a programming-language construct q Mutual exclusion constructs generated by the compiler. Internal data structures are invisible. Only one process is active in a monitor at the same time - high level mutual exclusion q Monitor disadvantages: o May be less efficient than lower-level synchronization o Not available from all programming languages Operating Systems, 2011, Danny Hendler & Amnon Meisels 2
Monitors Only one monitor procedure active at one time monitor example integer i; condition c; procedure producer( ); . . . end; procedure consumer( ); . . . Operatingend; Systems, 2011, Danny Hendler & Amnon Meisels enda presentation monitor; by Gadi Taubenfeld from IDC Slide taken from 3
Monitors: Condition variables q Monitors guarantee “automatic” mutual exclusion q Condition variables enable other types of synchronization q Condition variables support two operations: wait and signal q The monitor provides queuing for waiting procedures q When one procedure waits and another signals there are two ways to proceed: o The signaled operation will execute first: signaling operation immediately followed by block() or exit_monitor o The signaling operation is allowed to proceed Operating Systems, 2011, Danny Hendler & Amnon Meisels 4
type monitor-name = monitor variable declarations procedure entry P 1 (…); begin … end; procedure entry P 2 (…); begin … end; . . . procedure entry Pn (…); begin … end; begin initialization code Entry queue end Shared data Queues associated with x, y conditions x y … operations Initialization code Figure 6. 20 Monitor with Condition Variable Operating Systems, 2011, Danny Hendler & Amnon Meisels 5
Bounded Buffer with Monitors This code only works if a signaled thread is the next to enter the monitor 6 Operating Systems, 2011, Danny Hendler & Slide taken from a presentation by Gadi Taubenfeld from IDC
Monitors - some comments q Condition variables do not accumulate signals for later use q wait() must come before signal() in order to be signaled q Unlike sleep() and wakeup(), no race conditions, because monitors have mutual exclusion q More complex to implement – but done by compiler q Implementation issues: o How to interpret nested monitors? o How to define wait, priority scheduling, timeouts, aborts ? o How to Handle all exception conditions ? o How to interact with process creation and destruction ? Operating Systems, 2011, Danny Hendler & Amnon Meisels 7
Outline q Monitors o Monitors in Java q Barrier synchronization q The sleeping barber problem q Readers and writers q One-way tunnel Operating Systems, 2011, Danny Hendler & Amnon Meisels 8
Monitors in Java q Procedures can be designated as synchronized q “Strange” condition variables (either operating on a lock, or a single implicit one) q Synchronization operations: o Wait o Notifyall Operating Systems, 2011, Danny Hendler & Amnon Meisels 9
Producer-consumer in Java Class Producer extends Thread { void run() { while(true) { int item = produce. Item(); Bounded. Buffer. insert(item); }}} Class Consumer extends Thread { int item void run() { while(true) { item = Bounded. Buffer. extract(); consume(item); }}} Operating Systems, 2011, Danny Hendler & Amnon Meisels 10
Producer-consumer in Java (cont’d) Class Producer. Consumer { Producer prod = new Producer(); Consumer cons = new Consumer(); Bunded. Buffer bb = new Bounded. Buffer(); Public static void main(String[] args) { prod. start(); cons. start(); }} Operating Systems, 2011, Danny Hendler & Amnon Meisels 11
Producer-consumer in Java (cont’d) Class Bounded. Buffer { private int[] buffer = new int buff[N]; int first = 0, last = 0; public synchronized void insert(int item) { while((last – first) == N) What iswait(); the problem with this code? buff[last % N] = item; notify(); last++; } public synchronized int extract(int item) { while(last == first) wait(); int item = buff[first % N]; first++; notify(); return item; }} Operating Systems, 2011, Danny Hendler & Amnon Meisels 12
The problem with the code in the previous slide q Assume a buffer of size 1 q The buffer is empty, consumers 1, 2 enter the monitor and wait q A producer enters the monitor and fills it, performs a notify and exits. Consumer 1 is ready. q The producer enters the monitor again and waits. q Consumer 1 empties the buffer, performs a notify and exits. q Consumer 2 gets the signal and has to wait again. DEADLOCK. One must use notify. All()! Operating Systems, 2011, Danny Hendler & Amnon Meisels 13
Monitors in Java: comments q notify() does not have to be the last statement q wait() adds the calling Thread to the queue q a Thread performing notify() is not blocked just moves one waiting Thread to state ready q once the monitor is open, all queued ready Threads (including former waiting ones) are contesting for entry q To ensure correctness, wait() operations must be part of a conditionchecking loop Operating Systems, 2011, Danny Hendler & Amnon Meisels 14
Implementing Monitors with Semaphores – take 1 typedef int semaphore; mutex=1; void enter_monitor(void) down(mutex); void leave(void) up(mutex); { /*control access to monitor*/ { } } void leave_with_signal(semaphore c) { up(c) } void wait(semaphore c) { up(mutex); down (c); } /*only one-at-a-time*/ /*allow other processes in*/ /*c signals for leave*/ /*of the condition variable*/ /* block on a condition c */ /*allow other processes*/ /*block on the condition*/ Operating Systems, 2011, Danny Hendler & Amnon Meisels 15
Implementing Monitors with Semaphores - Correct! semaphore mutex = 1; cond c; void enter_monitor(void) { down(mutex); } void leave(void) { up(mutex); } void leave_with_signal(cond c) { if(c. count == 0) up(mutex); else {c. count--; up(c. s)} } void wait(cond c) { c. count++; up(mutex); down(c. s); } /* control access to monitor */ /* c = {count; semaphore} */ /* only one-at-a-time */ /* allow other processes in */ /* cond c is a struct */ /* no waiting, just leave. . */ /* /* block on a condition */ count waiting processes */ allow other processes */ block on the condition */ Operating Systems, 2011, Danny Hendler & Amnon Meisels 16 10/3/2020
Outline q Monitors o Monitors in Java q Barrier synchronization q The sleeping barber problem q Readers and writers q One-way tunnel Operating Systems, 2011, Danny Hendler & Amnon Meisels 17
Barriers q Useful for computations that proceed in phases q 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 Operating Systems, 2011, Danny Hendler & Amnon Meisels 18
The fetch-and-increment instruction Fetch-and-increment(w) do atomically prev: =w w: =w+1 return prev Operating Systems, 2011, Danny Hendler & Amnon Meisels 19
A simple barrier using fetch-and-inc shared integer counter=0, bit go local-go, local-counter Barrier() local-go : = go local-counter : = Fetch-and-increment(counter) if (local-counter = n) counter : = 0 go : = 1 -go else await (local-go ≠ go) Operating Systems, 2011, Danny Hendler & Amnon Meisels 20
Outline q Monitors o Monitors in Java q Barrier synchronization q The sleeping barber problem q Readers and writers q One-way tunnel Operating Systems, 2011, Danny Hendler & Amnon Meisels 21
The Sleeping Barber Problem Operating Systems, 2011, Danny Hendler & Amnon Meisels 22
The sleeping barber problem q Barber shop - one service provider; many customers q A finite waiting queue q One customer is served at a time q Service provider, barber sleeps when no customers are waiting q Customer leaves if shop is full q Customer sleeps while waiting in queue Operating Systems, 2011, Danny Hendler & Amnon Meisels 23
The sleeping barber: implementation #define CHAIRS 5 semaphore customers = 0; // number of waiting customers Semaphore barbers = 0; // number of available barbers: either 0 or 1 Semaphore mutex = 1; // mutex for accessing ‘waiting’ int waiting = 0; // copy of customers for reading void barber(void) { 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(); } } Operating Systems, 2011, Danny Hendler & Amnon Meisels 24
The sleeping barber: implementation (cont’d) void customer(void) { down(mutex); // access to `waiting’ if(waiting < CHAIRS) { waiting = waiting + 1; // increment waiting up(customers); // wake up barber up(mutex); // release ‘waiting’ down(barbers); // go to sleep if barbers=0 get_haircut(); } else { up(mutex); /* shop full. . leave */ }} Operating Systems, 2011, Danny Hendler & Amnon Meisels 25
The sleeping barber: correct synchronization #define CHAIRS 5 semaphore customers = 0; // number of waiting customers Semaphore barbers = 0; // number of available barbers: either 0 or 1 Semaphore mutex = 1; // mutex for accessing ‘waiting’ Semaphore synch = 0; // synchronizing the service operation int waiting = 0; // copy of customers for reading void barber(void) { 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) //wait for customer to leave } } Operating Systems, 2011, Danny Hendler & Amnon Meisels 26
The sleeping barber: correct synchronization (cont’d) void customer(void) { down(mutex); // access to `waiting’ if(waiting < CHAIRS) { waiting = waiting + 1; // increment waiting up(customers); // wake up barber up(mutex); // release ‘waiting’ down(barbers); // go to sleep if barbers=0 get_haircut(); up(sync); //synchronize service } else { up(mutex); }} /* shop full. . leave */ Operating Systems, 2011, Danny Hendler & Amnon Meisels 27
Outline q Monitors o Monitors in Java q Barrier synchronization q The sleeping barber problem q Readers and writers q One-way tunnel Operating Systems, 2011, Danny Hendler & Amnon Meisels 28
The readers and writers problem q Motivation: database access q Two groups of processes: readers, writers q Multiple readers may access database simultaneously q A writing process needs exclusive database access Operating Systems, 2011, Danny Hendler & Amnon Meisels 29
Readers and Writers: 1 st algorithm Int rc = 0 // # of reading processes semaphore mutex = 1; // controls access to rc semaphore db = 1; // controls database access void reader(void){ 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); } } void writer(void){ while(TRUE){ down(db); write_data_base() down(db) } Who is more likely to run: readers or writers? Operating Systems, 2011, Danny Hendler & Amnon Meisels 30
Comments on 1 st algorithm q No reader is kept waiting, waiting unless a writer has already obtained the db semaphore q Writer processes may starve - if readers keep coming in and hold the semaphore db q An alternative version of the readers-writers problem requires that no writer is kept waiting once it is “ready” when a writer is waiting, no new reader can start reading Operating Systems, 2011, Danny Hendler & Amnon Meisels 31
Readers and Writers: writers’ priority Int rc, wc = 0 // # of reading/writing processes semaphore Rmutex, Wmutex = 1; // controls readers/writers access to rc/wc semaphore Rdb, Wdb = 1; // controls readers/writers database access void reader(void){ 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); } } void writer(void){ 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) Operating Systems, 2011, Danny Hendler & Amnon Meisels 32
Comments on 2 nd algorithm q When readers are holding Wdb, Wdb the first writer to arrive obtains Rdb q All Readers arriving later are blocked on Rdb q all writers arriving later are blocked on Wmutex q only the last writer to leave Wdb releases Rdb – readers can wait… q If a writer and a few readers are waiting on Rdb, Rdb the writer may still have to wait for these readers If Rdb is unfair, the writer may again starve Operating Systems, 2011, Danny Hendler & Amnon Meisels 33
Readers and Writers: Writers improved writers’ priority Int rc, wc = 0 // # of reading/writing processes semaphore Rmutex, Wmutex, Mutex 2 = 1; semaphore Rdb, Wdb = 1; void reader(void){ while(TRUE){ down(Mutex 2) down(Rdb); down(Rmutex) rc = rc + 1; if(rc == 1) down(Wdb); up(Rmutex); up(Rdb) up(Mutex 2) read_data_base(); down(Rmutex); rc = rc - 1; if(rc == 0) up(Wdb); up(Rmutex); } } void writer(void){ 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) Operating Systems, 2011, Danny Hendler & Amnon Meisels 34
Improved writers' priority q After the first writer does down(Rdb) q The first reader that enters is blocked after doing down(Mutex 2) and before doing up(Mutex 2) q Thus no other readers can block on Rdb q This guarantees that the writer has to wait for at most a single reader q Even if the semaphore Rdb is unfair Operating Systems, 2011, Danny Hendler & Amnon Meisels 35
Readers-writers with Monitors Monitor reader_writer{ int number. Of. Readers = 0; boolean writing = FALSE; condition ok. To. Read, ok. To. Write; public: procedure start. Read() { if(writing || (not. Empty(ok. To. Read. queue))) ok. To. Read. wait; number. Of. Readers = number. Of. Readers + 1; ok. To. Read. signal; }; procedure finish. Read() { number. Of. Readers = number. Of. Readers - 1; if(number. Of. Readers == 0) ok. To. Write. signal; }; Operating Systems, 2011, Danny Hendler & Amnon Meisels 36
Readers-writers with Monitors (cont'd) procedure start. Write() { if((number. Of. Readers != 0) || writing) ok. To. Write. wait; writing = TRUE }; procedure finish. Write() { writing = FALSE; if(not. Empty(ok. To. Write. queue)) ok. To. Write. signal else ok. To. Read. signal; }; } Operating Systems, 2011, Danny Hendler & Amnon Meisels 37
Synchronization Problems q Monitors o Monitors in Java q Barrier synchronization q The sleeping barber problem q Readers and writers q One-way tunnel Operating Systems, 2011, Danny Hendler & Amnon Meisels 38
The one-way tunnel problem q One-way tunnel q Allows any number of processes in the same direction q If there is traffic in the opposite direction – have to wait q A special case of readers/writers Operating Systems, 2011, Danny Hendler & Amnon Meisels 39
Passing through a one-way Tunnel q Similar to Readers-Writers… q a solution must count[2] the number of processes inside the tunnel (in each direction) q a semaphore should be used for “use of the tunnel”, call it busy q waiting processes block on another semaphore waiting[2] - maintaining two “queues” q two functions (that share a semaphore for mutual exclusion) are performed by entering and leaving processes arrive(int direction) and leave(int direction) Operating Systems, 2011, Danny Hendler & Amnon Meisels 40
One-way tunnel - solution int count[2]; Semaphore mutex = 1, busy = 1; Semaphore waiting[2] = {1, 1}; void arrive(int direction) { down(waiting[direction]); down(mutex); count[direction] += 1; if(count[direction] == 1) up(mutex); down(busy) else up(mutex); up(waiting[direction]); } void leave(int direction) { down(mutex); count[direction] -= 1; if(count[direction] == 0) up(busy)} up(mutex); } Operating Systems, 2011, Danny Hendler & Amnon Meisels 41
Equivalence: Semaphores with Message passing q use a semaphore-process (mailbox) p p keeps the counter of the semaphore s o p 1 down(s) - send(p, down(s)); – receive(p, ack) if s <= 0 p does not send an acknowledgement o p 2 up(s) send(p, up(s)) if s <= 0 p sends the acknowledgement to a selected process – send (p 1, ack) Advantage – porting code to the distributed world… Operating Systems, 2011, Danny Hendler & Amnon Meisels 42
Synchronization in Solaris q Supports adaptive mutexes, condition variables, semaphores, readerwriter locks, turnstiles q Two types of mutex locks: o Spin – for high priority (kernel) threads o Adaptive – kernel threads can make a choice when encountering a lock § Spin-wait if lock is held by another running process § If holder is blocked – block also q Readers/writer locks: allow either multiple readers or a single writer to be in the critical section q Turnstiles are used to manage queues of threads waiting on mutex and synchronize wakeup o Assigned dynamically according to needs, to threads blocked on locks o Signal sent to highest-priority waiting thread Operating Systems, 2011, Danny Hendler & Amnon Meisels 43
- Slides: 43