Monitor Giving credit where it is due: The lecture notes are borrowed from Dr. I-Ling Yen at University of Texas at Dallas I have modified them and added new slides
Problems with Semaphores Correct use of semaphore operations may not be easy, since they may be scattered throughout a program:
Monitors A high-level abstraction that provides equivalent functionality to that of semaphores and that is easier to control The monitor construct has been implemented in a number of programming languages and as a program library A programmer does not need to manually write the entire synchronization code
Monitors monitor monitor-name { // shared variables declarations procedure P1 (…) { …. } … procedure Pn (…) {……} Initialization code (….) { … } … }
Monitor Protect shared objects within an abstraction Provide encapsulation Accesses to a shared object is confined within a monitor Provide mutual exclusive accesses No two process can be active at the same time within a monitor monitor Monitor already provides lock box and corresponding control mechanism
Shared Device Program with Monitor N devices in the system Use any of them as long as it is free monitor mutex_devices: free: array [0..N–1] of boolean; -- initialized to true int acquire () { for i := 0 to N–1 do if (free[i]) then { free[i] := false; return (i); } else return (–1); } void release (index: integer) { free[index] := true; }
Synchronization within a Hoare-style Monitor Monitor guarantees mutual exclusive accesses May still need synchronization E.g., shared device problem wait for device to become available E.g., bounded buffer problem wait for buffer to become full/empty Monitor guarantees mutual exclusive accesses May still need synchronization Monitor also provides condition variables To achieve conditional wait and support synchronization Associated with each condition variable A condition queue The wait and signal functions If wait inside a monitor Same as wait inside a lockbox protected by a semaphore (mutex) Has potential of deadlock Monitor provides mechanism to counter it
Synchronization within a Hoare-style Monitor monitor condition queue x condition variable y
Bounded Buffer Problem with a Hoare- style Monitor monitor bounded_buffer buffer: array [0..n-1] of item; in, out, counter: integer := 0; empty, full: condition; function deposit (item) function remove (&item) { if (counter = n) then { if (counter = 0) then full.wait; empty.wait; buffer[in] := item; item := buffer[out]; in := (in+1) % n; out := (out+1) % n; counter := counter + 1; counter := counter – 1; empty.signal; full.signal; } }
Bounded Buffer Problem with a Hoare- style Monitor Producer process: repeat produce item deposit (item); until false; Consumer process: repeat remove (item); consume item; until false;
Bounded Buffer Problem with a Hoare- style Monitor (Signal-and-Wait Discipline) monitor condition queue full empty function deposit (item) { if (counter = n) then full.wait; buffer[in] := item; in := (in+1) % n; counter := counter + 1; empty.signal; } function remove (&item) { if (counter = 0) then empty.wait; item := buffer[out]; out := (out+1) % n; counter := counter – 1; full.signal; }
Bounded Buffer Problem with a Hoare- style Monitor (Signal-and-Wait Discipline) monitor condition queue full empty function fun1 () { … empty.signal; …} function fun2 () { … empty.wait; …} A process signals and then must be blocked; signal-and-wait Process scheduling associated with a signal must be perfectly reliable
Bounded Buffer Problem with a Hoare- style Monitor (Signal-and-Wait Discipline) monitor condition queue full empty function deposit (item) { if (counter = n) then full.wait; buffer[in] := item; in := (in+1) % n; counter := counter + 1; empty.signal; } function remove (&item) { if (counter = 0) then empty.wait; item := buffer[out]; out := (out+1) % n; counter := counter – 1; full.signal; }
Bounded Buffer Problem with a Mesa Monitor (Signal-and-Continue Discipline) monitor bounded_buffer buffer: array [0..n-1] of item; in, out, counter: integer := 0; empty, full: condition; function deposit (item) function remove (&item) { while (counter = n) then { while (counter = 0) then full.wait; empty.wait; buffer[in] := item; item := buffer[out]; in := (in+1) % n; out := (out+1) % n; counter := counter + 1; counter := counter – 1; empty.notify; full. notify; } }
Bounded Buffer Problem with a Mesa Monitor (Signal-and-Continue Discipline) monitor condition queue full empty watchdog timer function deposit (item) { while (counter = n) then full.wait; buffer[in] := item; in := (in+1) % n; counter := counter + 1; empty.notify; } function remove (&item) { while (counter = 0) then empty.wait; item := buffer[out]; out := (out+1) % n; counter := counter – 1; full.notify; }
Monitor Monitor provides encapsulation Accesses to a shared object is confined within a monitor Easier to debug the code E.g., bounded buffer problem, deposit & remove functions What should be encapsulated? Too much reduce concurrency Some part of the code that can be executed concurrently, if encapsulated in the monitor, can cause reduced concurrency