140 likes | 342 Views
Monitors. mutexes printer = -1 scanner = 0. P 1. P 2. P(printer) P(scanner) - CS -. P(scanner) P(printer) - CS -. blocked. blocked. A Problem with Semaphores. Consider the following scenario:. timer interrupt.
E N D
mutexes printer = -1 scanner = 0 P1 P2 P(printer) P(scanner) - CS - P(scanner) P(printer) - CS - blocked blocked A Problem with Semaphores Consider the following scenario: timer interrupt If there is a timer interrupt after the call to P(printer) but before P(scanner) in P1 then P2 will be able to start and call P(scanner). But if this occurs, then both processes will become deadlocked.
Introducing Monitors • the term “monitor” (in regard to access control) coined by C.A.R. Hoare in 1974 • all variables and functions for access control related to a specific data source are contained within a single structure • monitors act as “barriers” for data allowing access via programmer-defined functions • mutexes and calls to P() and V() previously scattered throughout code are no longer necessary • processes need no longer be aware of each other for access control; rather, they need only knowledge of monitor functions
R1 R2 Rn Shared Data Monitor W1 W2 Wn Protection of Shared Data via Monitor Reader and writer processes R and W are requiring access to shared data. Such access is controlled by a single monitor. (More on the readers/writers problem later.)
Monitor internals • process flow control is accomplished via calls to wait() and signal() that each take a condition variable as the parameter • wait(cond)suspends the calling process and places it into a queue • signal(cond) resumes the execution of an enqueued process previously suspended by a call to wait(cond) • think of a monitor as an object instantiated from a special class • conditions are private data members of the monitor • wait() and signal() are protected functions inherently available within all monitors • calls to wait() and signal() are made within the implementation of user-defined public functions of a derived monitor
Monitor internals • by design, only one process may be inside of a monitor at any given instant • parallel execution of monitor functions is impossible • eliminates possible race conditions while determining if a process should wait • any call to signal(cond) when no suspended processes are enqueued is ignored • contrast this with calls to V(mutex) where mutex will be always be incremented regardless of the number of calls to P(mutex)
condition clear; bool inUse; acquire() if (inUse) wait(clear); inUse = true; release() inUse = false; signal(clear); Simple example:Mutually exclusive access via Monitor monitor access • when some process P1 wants access to currently unshared data, it calls acquire() and is allowed to proceed into its critical section • if some different process P2 then calls acquire() prior to P1 releasing its hold, then P2 is suspended and enqueued upon the internal call to wait(clear) and will be blocked from reaching its critical section • upon P1 calling signal(clear) via release(), P2 is dequeued and allowed to continue execution
P2 P1 access.acquire() {critical section} access.release() access.acquire() {critical section} access.release() Demonstration of Exclusive Access via Monitor Operations: wait(clear) signal(clear) Entry Queue P2 P1 As P1 has not yet released the resource, P2 is enqueued by its call to wait(clear). Signal is sent by P1 to condition variable clear, thus dequeueing P2 monitor access Conditions acquire() clear release() States inUse= false true No more processes!
A more complicated example: “Readers and Writers problem” as a Monitor • must support multiple reader and writer processes • if a single reader enters a vacant data area, any or all readers (but not writers) may enter • if a writer enters a vacant data area, no readers or other writers may enter • writer must wait for readers and other writers to vacate data area prior to entry
int readers; bool someonewriting; condition readallowed, writeallowed; monitor RaW Rn Wn beginreading() RaW.beginreading() {critical section} RaW.endreading() RaW.beginwriting() {critical section} RaW.endwriting() endreading() beginwriting() endwriting() “Readers and Writers” as a Monitor A solution to the “readers and writers” problem at a glance processes
Pseudocode Implementation monitor RaW var readers: integer; someonewriting: boolean; readallowed, writeallowed: condition; procedure beginreading { if someonewriting or queue(writeallowed) then wait(readallowed); readers := readers + 1; signal(readallowed);} procedure endwriting { readers := readers – 1; if readers = 0 then signal(writeallowed);} procedure beginwriting { if (reader != 0 or someonewriting) then wait(writeallowed); someonewriting := true; } procedure endwriting { someonewriting := false; if queue(readallowed) then signal(readallowed) else signal(writeallowed); } { readers := 0; someonewriting := false; } // end readers & writers