// This file defines class "rwMonitor", a monitor for the reader/writer // problem. It defines methods startRead, endRead, startWrite, endWrite. // // The synchronization (readers have priority) is the same as was used // in lab 3. Where lab 3 used semaphores, a monitor is used here. // // startRead, endRead, startWrite, and endWrite are declared to be // "synchronized" methods. The "synchronized" keyword tells the Java // compiler to provide mutually exclusive access. At any given time, at most // one thread can be executing any of the code inside these synchronized // methods. For example, if thread R1 is executing startRead, then any // other threads that call startRead, endRead, startWrite, or endWrite // have to wait. The compiler generates code to do this, both to make the // calling threads wait, and to arrange that when R1 finishes execution of // StartRead, one of the waiting threads is allowed to continue executing. public class rwMonitor { private int readcount; // A count of the number of readers who are // currently reading. private int writecount; // A count of the number of writers who are // currently writing (0 or 1). // This is the constructor for class rwMonitor. public rwMonitor() { readcount = 0; writecount = 0; } // end of the constructor for class "rwMonitor" // ---- method startRead ---- // If there are any writers active (tested by "writecount>0") then wait // until another thread notifies us. // // Once no writers are active, the reader can go ahead. Record // this by incrementing readcount. public synchronized void startRead () { while (writecount > 0) { try { wait(); } catch (Exception e) {}; // wait for "notify()" } // end of the while loop readcount++; } // end of "startRead" method // ---- method endRead ---- // The endRead method decrements readcount. // If readcount is now zero, then notify all the waiting threads. // All of the waiting threads will be writers; any readers that showed // up would not wait in "startRead". All of the waiting writers are // awakened, and they all compete to get the lock for the monitor. The // first writer to get in will set writecount to 1, and will start writing. // The other writers will find that writecount still is greater than 0, and // they will wait() again. public synchronized void endRead () { readcount--; if (readcount == 0) { notifyAll(); } // if readcount = 0 } // end of "endRead" method // ---- method startWrite ---- // The startWrite method waits until no readers or writers are active. // Then the writer can go ahead. Record this by incrementing writecount. public synchronized void startWrite () { while (readcount > 0 || writecount > 0) { try { wait(); } catch (Exception e) {}; // wait for notify() } // end of the while loop writecount++; } // end of "startWrite" method // ---- method endWrite ---- // The endWrite method decrements writecount and notifies all waiting // processes. // // The notifyAll wakes up all waiting threads (both readers and // writers). All the readers will start, or one of the writers will start. // The other threads will wait() again. // // As an example, suppose that 3 reader and 2 writer threads are waiting. // Each of these threads is part-way through executing a synchronized // routine (startRead, endRead, startWrite, endWrite) and is stuck at // a "wait" statement, where it has "stepped out" of the monitor. (In other // words, it no longer holds the lock for the monitor.) // The notifyAll() wakes up all 5 of the waiting threads, in some // arbitrary order. The threads execute one at a time (stepping // back in to the monitor, to execute more of the synchronized // routine that they called.) If it happens that a reader thread // gets the monitor lock first, it finds that writecount == 0 so it sets // readcount to 1 and starts reading. The writers that are awakened notice // that readcount>0, so they again execute wait(). The other readers // notice that writecount is still zero, so they start. Now we have three // readers active, readcount = 3, writecount = 0, and two writers still // waiting in the startWrite method. public synchronized void endWrite () { writecount--; notifyAll(); // notify all processes that are waiting. This will // start all waiting readers, or one waiting writer. } // end of "endWrite" method } // end of class "rwMonitor"