Higher Level Mechanisms for Building Critical Sections zSemaphores yVery primitive (Specifying direct start and stop of threads) ySimple (Hard to program with, but easy to get) zMonitors yHigher level than semaphores (language support). More abstract zMessages ySimple model of communication and synchronization based on atomic transfer of data across a channel yDirect application to distributed systems
Semaphores zAbstract data type with an internal counter that is accessed atomically yP(s) xwait for s.counter > 0; decrement s.counter. yV(s) xincrement s
Binary Semaphores zUsed for mutual exclusion yOnly one process can access a critical section at a time. yTo enter the critical section, P on the semaphore. yWhen leaving the critical section, V on the semaphore. zCounter can take on two values: 0,1 yinitially, count is 1. yP(s) : xif s.count > 0 then s.count = 0 xif s.count == 0 then wait yV(sem): count(sem) = 1;
Counting semaphores zOne “resource” with the mutual exclusion example. ythe resource is the critical section. zWhen you have a lot of resources and you want to hand them out zWant to use COUNTING SEMAPHORES: [0..N] yinitially, count == N. xP(sem): if count(sem) > 0, count(sem) --; if count(sem) == 0 wait; xV(sem): count(sem)++;
Bounded Buffer Semaphore Implementation var mutex: semaphore = 1; //mutual exclusion to shared data empty: semaphore = n; //count of empty buffers (all empty to start) full: semaphore = 0; //count of full buffers (none full to start) producer: wait(empty); //one fewer buffer, block if none available wait(mutex); //get access to pointers signal(mutex); //done with pointers signal(full); //note one more full buffer consumer: wait(full); //wait until there’s a full buffer wait(mutex); //get access to pointers signal(mutex) ; //done with pointers signal(empty) ; //note there’s an empty buffer
Synchronization with Semaphores zSemaphores can be used to solve any of the traditional synchronization problems, but suffer from several problems: 1. semaphores are essentially shared global variables 2. there is no connection between the semaphore and the data being controlled by the semaphore 3. Use same mechanism for scheduling and synchronization. 4. they can be accessed from anywhere in the code 5. there is no control or guarantee of proper usage zSemaphores are sometimes hard to use and prone to bugs. zOne solution is to provide programming language support for synchronization. yWhy does putting something in the language make it harder to misuse?
Monitors zA monitor is a programming language construct that supports controlled access to shared data. zA monitor is a module that encapsulates: 1. some shared data structures 2. procedures that operate on that shared data 3. synchronization between concurrent processes that invoke those procedures zA monitor protects the data from unstructured access. zThe monitor guarantees that processes trying to access the data through its procedures interact only in legitimate ways.
Monitor Facilities zA monitor guarantees mutual exclusion yOnly one process can be executing within monitor at any time yIf a second process tries to enter a monitor procedure, it blocks until the first has left the monitor yMore restrictive than semaphores; easier to use most of the time zOnce in the monitor, a process may discover that it cannot continue, and may wish to sleep, or it may wish to allow a waiting process to continue. yCondition Variables provide synchronization within the monitor so that processes can wait or signal others to continue.
Condition Variables zThe actual logic is provided by the program, not by the condition variable BOOLEAN NotEnoughMilk, MilkInTransit; CONDITION MilkCondition IF (NotEnoughMilk AND MilkInTransit) THEN Condition.Wait(MilkCondition); zOperations on condition variables yCondition.Wait(c) xrelease monitor lock, wait for someone to signal condition yCondition.Signal(c) xwakeup one waiting thread
Basic Monitor Structure resource: monitor begin busy: boolean; free: condition; procedure acquire; begin if busy then free.wait; busy = true; end procedure release; begin busy=false; free.signal; end busy=false ; initialize busy end
Monitors and Semaphores zMonitors and Semaphores can be implemented in terms of each other. E.g., to implement monitors with semaphores, we need: ymutex : a semaphore to control entry to the monitor (initialize to 1) ynext : a semaphore to suspend a process when it signals another (initialize to 0) ynext-count : integer # of processes waiting due to signals yx-sem : a semaphore to suspend a process on a wait (initialized to 0) [one semaphore for each condition] yx-count: integer # of processes waiting due to waiting on condition [one for each condition]
Monitors implemented with Semaphores P(mutex); if next-count > 0 then V(next) else V(mutex); x.wait: x-count:=x-count+1; if next-count>0 then V(next) else V (mutex); P(x-sem); x-count:=xcount-1; x.signal if x-count>0 then begin next-count:=next-count+1; V(x-sem); P(next); next-count:=next-count-1; end; //General entry wrapper for all //operations.
Two kinds of Monitors zHOARE Monitors ySIGNAL(c) xRun waiter immediately. Signaler blocks right now xCondition is guaranteed to hold when blocker runs xBut, signaler must RESTORE MONITOR INVARIANTS before signaling zMESA Monitors ySIGNAL(c) xwaiter is made ready, but the signaler continues xCondition is not necessarily true when the waiter runs again xSignaler must not restore invariant until it leaves the MONITOR xWAKEUP is only a HINT that something must have changed
Examples zHOARE if (NotReady) Condition.Wait(C); zMESA while (NotReady) Condition.Wait(C); zHoare monitor simplifies proof of correctness and leaves less to “chance.” zMESA monitor easier to use ymore efficient xfewer switches xdirectly supports broadcast.
Synchronization with Monitors zThree patterns of deadlock using monitors yInside a single monitor, two processes do a WAIT, each expecting to be awakened by the other - logical error with the monitor yA cyclic calling pattern between two monitors - partial ordering yTwo-level data abstraction (M calls N, N waits for a condition to be set by another process that enters N through M) - break M into two parts zMonitor are intended as primitive building blocks for more complex scheduling policies zMonitors still have problems: yProcesses must make calls on monitor procedures in the correct order yProcesses cannot ignore control imposed by monitor and enter CS directly zSolution yMessage passing for synchronization yACL (access control list) and capabilities for protection
IPC (Inter-Processor communication) zShared memory - Communicate data implicitly via load and store operations zMessage passing - Communicate data by explicitly passing message among processors ySynchronous (blocking) xRPC (Remote Procedure Call) xSender requests, receiver replies yAsynchronous (non-blocking) xData sent directly to consumer process w/o requesting xReceiver blocks if it tries to receive message before it arrives xSender blocks if receiver has not consumed an earlier message xMPI (message passing interface)