Monitors

Semaphores work just fine for synchronization, but they are totally unstructured (in the same sense that GOTOs and pointers are unstructured). There has been some work in creating language features to provide mutual exclusion. Prominent in these efforts has been the monitor.

A monitor simply defines some code to be a critical section, and depends on the compiler to insert synchronization primitives as needed. It would be very simple to create a monitor that looked like a C++ class; something like

monitor {
 public:
   proc1;
   proc2;
};

The semantics of this is that appropriate entry and exit code (like a boolean semaphore down and up) is inserted for any time a call is made from outside the monitor to inside the monitor.

This provides mutual exclusion, but not resource control (remember bounded buffer required both). Monitors provide a mechanism for resource control though ``condition variables'' and signal and wait procedures.

A condition is something you need to be true before you can continue. If you test for the condition and it doesn't hold, you need to call wait to wait for it to become true. If you cause a condition to become true, then you call signal to notify anybody waiting on it that it has become true. When you call wait, you release the monitor lock; otherwise, nobody else could get in to let you go again.

As an aside, there have been many subtle variations on the precise semantics of signal and wait. Here's a brief writeup of Hoare and Mesa monitors.

Here's the producer-consumer problem from last time, recoded using a monitor.

ProducerConsumerMonitor
while (1) {
    item = produce();
    put(item);
}
        
while (1) {
    item = get();
    consume(item);
}
        
monitor {
    int space = N;
    int full = 0;
    condition cspace;
    condition cfull;
        
    Item get {
        if (full == 0) wait(cfull);
        // get item from queue
        full--;
        space++;
        if (space == 1) signal(cspace);
        return(item);
    }

    void put(Item item) {
        if (space == 0) wait(cspace);
        // put item on queue
        full++;
        space--;
        if (full == 1) signal(cfull);
    }
        

This moves the real work into the put and get routines; the program itself doesn't have to worry about it.


Last modified: Mon Sep 12 10:42:04 MDT 2005