semaphores and monitors
play

Semaphores and Monitors: Past few lectures: High-level - PDF document

Synchronization Constructs Synchronization Coordinating execution of multiple threads that share data structures Semaphores and Monitors: Past few lectures: High-level Synchronization Constructs Locks: provide mutual


  1. Synchronization ¡Constructs ¡ ¡ Synchronization Ø Coordinating execution of multiple threads that share data structures Semaphores and Monitors: Past few lectures: High-level Synchronization Constructs Ø Locks: provide mutual exclusion Ø Condition variables: provide conditional synchronization Today: Historical perspective Ø Semaphores ❖ Introduced by Dijkstra in 1960s ❖ Main synchronization primitives in early operating systems Ø Monitors ❖ Alternate high-level language constructs ❖ Proposed by independently Hoare and Hansen in the 1970s 1 2 Key ¡idea ¡of ¡Semaphores ¡vs. ¡Locks ¡ Semaphores ¡ Study these for history and compatibility Locks: Mutual exclusion only (1-exclusion) Ø Don’t use semaphores in new code A non-negative integer variable with two atomic and isolated operations Semaphores: k-exclusion Ø k == 1, equivalent to a lock Semaphore à P() ( Passeren ; wait) ❖ Sometimes called a mutex, or binary If sem > 0, then decrement sem by 1 Otherwise “ wait ” until sem > 0 and semaphore then decrement Ø k == 2+, up to k threads at a time Semaphore à V() ( Vrijgeven ; signal) Many semaphore implementations use “up” and “down”, Increment sem by 1 rather than Dutch names (P and V, respectively) Wake up a thread waiting in P() Ø ‘cause how many programmers speak Dutch? Semaphore starts at k We assume that a semaphore is fair Ø Acquire with down(), which decrements the count Ø No thread t that is blocked on a P() operation remains blocked if the V() ❖ Blocks if count is 0 operation on the semaphore is invoked infinitely often Ø In practice, FIFO is mostly used, transforming the set into a queue. Ø Release with up(), which increments the count and never blocks 3 4 Important ¡properties ¡of ¡Semaphores ¡ Semaphores are non-negative integers How many possible values can a binary semaphore take? The only operations you can use to change the value of a semaphore are P()/down() and V()/up() (except for the initial Ø A. 0 setup) Ø B. 1 Ø P()/down() can block, but V()/up() never blocks Ø C. 2 Semaphores are used both for Ø D. 3 Ø Mutual exclusion, and Ø E. 4 Ø Conditional synchronization Two types of semaphores Ø Binary semaphores: Can either be 0 or 1 Ø General/Counting semaphores: Can take any non-negative value Ø Binary semaphores are as expressive as general semaphores (given one can implement the other) 5 6

  2. Coke ¡Machine ¡Example ¡ Using ¡Semaphores ¡for ¡Mutual ¡Exclusion ¡ Coke machine as a shared buffer Use a binary semaphore for mutual exclusion Two types of users Semaphore = new Semaphore(1); Ø Producer: Restocks the coke machine Semaphore à P(); Ø Consumer: Removes coke from the machine Critical Section; Requirements Semaphore à V(); Ø Only a single person can access the machine at any time Using Semaphores for producer-consumer with bounded buffer Ø If the machine is out of coke, wait until coke is restocked Ø If machine is full, wait for consumers to drink coke prior to restocking Use a separate int count; How will we implement this? semaphore for Semaphore mutex; each Ø How many lock and condition variables do we need? Semaphore fullBuffers; constraint Semaphore emptyBuffers; ❖ A. 1 B. 2 C. 3 D. 4 E. 5 7 8 Revisiting ¡Coke ¡Machine ¡Example ¡ Implementing ¡Semaphores ¡ Semaphore::P() { Class CokeMachine{ if (0 > atomic_dec(&value)) { … Put TCB on wait queue for semaphore; int count; Switch(); // dispatch a ready thread Semaphore new mutex(1); atomic_inc(&value); Semaphores new fullBuffers(0); } Semaphores new emptyBuffers(numBuffers); } } Semaphore::V() { int notify = atomic_inc(&value); CokeMachine::Deposit(){ CokeMachine::Remove(){ Does this work? // atomic_inc returns new value emptyBuffers à P(); fullBuffers à P(); if (notify <= 0) { mutex à P(); mutex à P(); Add coke to the machine; Move a waiting thread to ready queue; Remove coke from to the machine; } count++; count--; mutex à V(); } mutex à V(); fullBuffers à V(); emptyBuffers à V(); value: } } 1..k = Resource available 0 = All resources used, no waiters Does the order of P matter? Order of V matter? <0 = -1 * number of waiters 9 10 Implementing ¡Semaphores ¡ The ¡Problem ¡with ¡Semaphores ¡ Semaphore::P() { Semaphores are used for dual purpose while (0 > atomic_dec(&value)) { Ø Mutual exclusion Put TCB on wait queue for semaphore; Ø Conditional synchronization Switch(); // dispatch a ready thread atomic_inc(&value); Difficult to read/develop code } } Waiting for condition is independent of mutual exclusion Ø Programmer needs to be clever about using semaphores Semaphore::V() { int notify = atomic_inc(&value); // atomic_inc returns new value CokeMachine::Deposit(){ CokeMachine::Remove(){ if (notify <= 0) { emptyBuffers à P(); fullBuffers à P(); Move a waiting thread to ready queue; mutex à P(); mutex à P(); } Add coke to the machine; Remove coke from to the machine; } count++; count--; mutex à V(); value: mutex à V(); fullBuffers à V(); emptyBuffers à V(); 1..k = Resource available } } 0 = All resources used, no waiters <0 = -1 * number of waiters 11 12

  3. Introducing ¡Monitors ¡ Critical ¡Section: ¡Monitors ¡ Separate the concerns of mutual exclusion and conditional Basic idea: synchronization Ø Restrict programming model What is a monitor? Ø Permit access to shared variables only within a critical Ø One lock, and section Ø Zero or more condition variables for managing concurrent access to shared data General program structure General approach: Ø Entry section Ø Collect related shared data into an object/module ❖ “ Lock ” before entering critical section ❖ Wait if already locked, or invariant doesn’t hold Ø Define methods for accessing the shared data ❖ Key point: synchronization may involve wait Monitors first introduced as programming language construct Ø Critical section code Ø Calling a method defined in the monitor automatically acquires the Ø Exit section lock ❖ “ Unlock ” when leaving the critical section Ø Examples: Mesa, Java (synchronized methods) Monitors also define a programming convention Object-oriented programming style Ø Can be used in any language (C, C++, … ) Ø Associate a lock with each shared object Ø Methods that access shared object are critical sections Ø Acquire/release locks when entering/exiting a method that defines a critical section 13 14 Remember ¡Condition ¡Variables ¡ ¡ So ¡what ¡is ¡the ¡big ¡idea? ¡ Locks (Editorial) Integrate idea of condition variable with Ø Provide mutual exclusion language Ø Support two methods ❖ Lock::Acquire() – wait until lock is free, then grab it Ø Facilitate proof ❖ Lock::Release() – release the lock, waking up a waiter, if any Ø Avoid error-prone boiler-plate code Condition variables Ø Support conditional synchronization Ø Three operations ❖ Wait(): Release lock; wait for the condition to become true; reacquire lock upon return (Java wait()) ❖ Signal(): Wake up a waiter, if any (Java notify()) ❖ Broadcast(): Wake up all the waiters (Java notifyAll()) Ø Two semantics for implementation of wait() and signal() ❖ Hoare monitor semantics ❖ Hansen (Mesa) monitor semantics 15 16 Coke ¡Machine ¡– ¡Example ¡Monitor ¡ Monitors: ¡Recap ¡ Class CokeMachine{ Does the order of … Lock acquire and release: often incorporated into aquire/while(){wait} Lock lock; method definitions on object matter? int count = 0; Condition notFull, notEmpty; Ø E.g., Java’s synchronized methods } Order of release/signal Ø Programmer may not have to explicitly acquire/release matter? But, methods on a monitor object do execute under mutual exclusion CokeMachine::Deposit(){ CokeMachine::Remove(){ Introduce idea of condition variable lock à acquire(); lock à acquire(); while (count == n) { while (count == 0) { notFull.wait(&lock); } notEmpty.wait(&lock); } Add coke to the machine; Remove coke from to the machine; count++; count--; notEmpty.signal(); notFull.signal(); lock à release(); lock à release(); } } 17 18

Recommend


More recommend