160 likes | 327 Views
Higher Level Mechanisms for Building Critical Sections. Semaphores Very primitive (Specifying direct start and stop of threads) Simple (Hard to program with, but easy to get) Monitors Higher level than semaphores (language support). More abstract Messages
E N D
Higher Level Mechanisms for Building Critical Sections • Semaphores • Very primitive (Specifying direct start and stop of threads) • Simple (Hard to program with, but easy to get) • Monitors • Higher level than semaphores (language support). More abstract • Messages • Simple model of communication and synchronization based on atomic transfer of data across a channel • Direct application to distributed systems
Semaphores • Abstract data type with an internal counter that is accessed atomically • P(s) • wait for s.counter > 0; decrement s.counter. • V(s) • increment s
Binary Semaphores • Used for mutual exclusion • Only one process can access a critical section at a time. • To enter the critical section, P on the semaphore. • When leaving the critical section, V on the semaphore. • Counter can take on two values: 0,1 • initially, count is 1. • P(s) : • if s.count > 0 then s.count = 0 • if s.count == 0 then wait • V(sem): count(sem) = 1;
Counting semaphores • One “resource” with the mutual exclusion example. • the resource is the critical section. • When you have a lot of resources and you want to hand them out • Want to use COUNTING SEMAPHORES: [0..N] • initially, count == N. • P(sem): if count(sem) > 0, count(sem) --; • if count(sem) == 0 wait; • V(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 <add item to buffer> 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 <remove item from buffer> signal(mutex) ; //done with pointers signal(empty) ; //note there’s an empty buffer <use the item>
Synchronization with Semaphores • Semaphores 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 • Semaphores are sometimes hard to use and prone to bugs. • One solution is to provide programming language support for synchronization. • Why does putting something in the language make it harder to misuse?
Monitors • A monitor is a programming language construct that supports controlled access to shared data. • A 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 • A monitor protects the data from unstructured access. • The monitor guarantees that processes trying to access the data through its procedures interact only in legitimate ways.
Monitor Facilities • A monitor guarantees mutual exclusion • Only one process can be executing within monitor at any time • If a second process tries to enter a monitor procedure, it blocks until the first has left the monitor • More restrictive than semaphores; easier to use most of the time • Once 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. • Condition Variables provide synchronization within the monitor so that processes can wait or signal others to continue.
Condition Variables • The 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); • Operations on condition variables • Condition.Wait(c) • release monitor lock, wait for someone to signal condition • Condition.Signal(c) • wakeup 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 • Monitors and Semaphores can be implemented in terms of each other. E.g., to implement monitors with semaphores, we need: • mutex : a semaphore to control entry to the monitor (initialize to 1) • next : a semaphore to suspend a process when it signals another (initialize to 0) • next-count : integer # of processes waiting due to signals • x-sem : a semaphore to suspend a process on a wait (initialized to 0) [one semaphore for each condition] • x-count: integer # of processes waiting due to waiting on condition [one for each condition]
Monitors implemented with Semaphores • P(mutex); • < body of operation> • 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 • HOARE Monitors • SIGNAL(c) • Run waiter immediately. Signaler blocks right now • Condition is guaranteed to hold when blocker runs • But, signaler must RESTORE MONITOR INVARIANTS before signaling • MESA Monitors • SIGNAL(c) • waiter is made ready, but the signaler continues • Condition is not necessarily true when the waiter runs again • Signaler must not restore invariant until it leaves the MONITOR • WAKEUP is only a HINT that something must have changed
Examples • HOARE if (NotReady) Condition.Wait(C); • MESA while (NotReady) Condition.Wait(C); • Hoare monitor simplifies proof of correctness and leaves less to “chance.” • MESA monitor easier to use • more efficient • fewer switches • directly supports broadcast.
Synchronization with Monitors • Three patterns of deadlock using monitors • Inside a single monitor, two processes do a WAIT, each expecting to be awakened by the other - logical error with the monitor • A cyclic calling pattern between two monitors - partial ordering • Two-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 • Monitor are intended as primitive building blocks for more complex scheduling policies • Monitors still have problems: • Processes must make calls on monitor procedures in the correct order • Processes cannot ignore control imposed by monitor and enter CS directly • Solution • Message passing for synchronization • ACL (access control list) and capabilities for protection
IPC (Inter-Processor communication) • Shared memory - Communicate data implicitly via load and store operations • Message passing - Communicate data by explicitly passing message among processors • Synchronous (blocking) • RPC (Remote Procedure Call) • Sender requests, receiver replies • Asynchronous (non-blocking) • Data sent directly to consumer process w/o requesting • Receiver blocks if it tries to receive message before it arrives • Sender blocks if receiver has not consumed an earlier message • MPI (message passing interface)