import java.awt.*; import java.util.*; import java.io.*; /* The only part of this file you should need to pay any attention to is the Rw class, which is the monitor that solves the readers/writers problem (ensuring that if any thread has write access, no other thread has either read or write access). Even within the Rw class you can ignore the "main" procedure, which just creates a graphical user interface control panel to allow you to interactively demo the behavior. */ public class Rw{ public static void main(String[] args){ new ControlPanel(new Rw()); } public synchronized void acquireReadAccess() throws InterruptedException{ while(numWriters > 0) wait(); numReaders++; } /* The below version of acquireWriteAccess allows a writer to "starved" (i.e., wait indefinitely) by a steady stream of readers with overlapping read periods, so that even those readers who arrive after the writer wind up getting to read while the writer sits and waits. Your assignment is to come up with a starvation-free replacement for this method. This is not intended to be a major programming project: it can be done without needing any changes outside this one method and with the new version of this method only being a few lines longer than the old. */ public synchronized void acquireWriteAccess() throws InterruptedException{ while(numReaders + numWriters > 0) wait(); numWriters++; } public synchronized void releaseReadAccess(){ if(--numReaders == 0) notifyAll(); } public synchronized void releaseWriteAccess(){ if(--numWriters == 0) notifyAll(); } int numReaders = 0; int numWriters = 0; } class ControlPanel extends Frame{ public ControlPanel(Rw controller){ theController = controller; setTitle("Readers/Writers demo"); setLayout(new GridLayout(1, 2)); add(new Button("Read")); add(new Button("Write")); resize(200, 70); show(); } public boolean handleEvent(Event evt) { if (evt.id == Event.WINDOW_DESTROY) System.exit(0); return super.handleEvent(evt); } public boolean action(Event evt, Object arg) { if(arg.equals("Read")){ new Reader(theController).start(); return true; } else if(arg.equals("Write")){ new Writer(theController).start(); return true; } else{ return super.action(evt, arg); } } Rw theController; } class Reader extends Thread{ public Reader(Rw controller){ id = count++; theController = controller; } public void run(){ System.out.println("Reader number " + id + " arrives"); try{ theController.acquireReadAccess(); System.out.println("Reader number " + id + " starts to read"); sleep((long) (minSleep + Math.random() * (maxSleep - minSleep))); } catch(InterruptedException e){ System.err.println("A reader was interrupted. Exiting."); System.exit(1); } System.out.println("Reader number " + id + " finishes reading"); theController.releaseReadAccess(); } static int count = 0; int id; Rw theController; static final int minSleep = 1000; // minimum 1000 ms = 1 second static final int maxSleep = 5000; // minimum 5000 ms = 5 seconds } class Writer extends Thread{ public Writer(Rw controller){ id = count++; theController = controller; } public void run(){ System.out.println("Writer number " + id + " arrives"); try{ theController.acquireWriteAccess(); System.out.println("Writer number " + id + " starts to write"); sleep((long) (minSleep + Math.random() * (maxSleep - minSleep))); } catch(InterruptedException e){ System.err.println("A writer was interrupted. Exiting"); System.exit(1); } System.out.println("Writer number " + id + " finishes writing"); theController.releaseWriteAccess(); } static int count = 0; int id; Rw theController; static final int minSleep = 1000; // minimum 1000 ms = 1 second static final int maxSleep = 5000; // minimum 5000 ms = 5 seconds }