Friday, 13 February 2009

Readers Writers Problem प्रॉब्लम solution

Problem Statement: Suppose there are N readers who want to read and N writers who want to write to same file. Readers should be able to write concurrently, but only one writer can write at a time. We need to design a stategy so that both readers and writers get fair chance and no one is starved.

Solution: When there are some readers currently reading and a writer arrives, it has to wait until the last reader finishes reading, and new readers that arrive cannot join the existing readers, they will have to wait until the waiting writer finishes. New reader can read immediately if there is no writer either writing or waiting. New writer can write immediately if there are no readers currently reading, or some writer currently writing/waiting. Writers will get chance to write in the order they arrive(FIFO).
import java.util.Vector;

/**
* Suppose there are n readers reading concurrently and a writer comes, writer has to wait until the
* currently active readers finish their job. But no new readers will be allowed to join the existing readers
* when a writer is already waiting. New readers can read immediately only if there are no waiting writers.
*
* When a writer finishes writing, waiting readers if any will get a chance to read, and when they finish
* they will notify waiting writers if any to start writing.
*
* Writers will get chance to write in FIFO order.
*
* Any reader/Writer who wants to perform reading/writing should call getControllerInstance() API
* and do perform the reading/writing like this:
*
* Controller ctl = ReadersWritersLock.getControllerInstance();
* ctl.beforeRead() / ctl.beforeWrite();
* //READ/WRITE OPERATION
* ctl.afterRead() / ctl.afterWrite();
*
*/

class ReadersWritersLock {
static Controller ctl;


//Any Reader/Writer should obtain a reference to Controller Instance before reading/writing
public static Controller getControllerInstance() {
return Controller.getControllerInstance();
}

public static void main (String argv[]) {
ctl = getControllerInstance();

new Reader1(ctl).start();
new Reader2(ctl).start();
new Writer1(ctl).start();
new Writer2(ctl).start();
}
}

class Reader1 extends Thread {
private Controller ctl;

Reader1(Controller c) { ctl = c;}

public void run()
{
while (true) {
ctl.beforeRead();
System.out.println("reader1 reading:");
//READ OPERATION
System.out.println("done reading");
ctl.afterRead();
}
} // end public void run()
}

class Reader2 extends Thread {
private Controller ctl;

Reader2(Controller c) { ctl = c;}

public void run()
{
while (true) {
ctl.beforeRead();
System.out.println("reader2 reading:");
//READ OPERATION
System.out.println("done reading");
ctl.afterRead();
}
} // end public void run()
}

class Writer1 extends Thread {
private Controller ctl;

Writer1(Controller c) { ctl = c;}

public void run()
{
while (true) {
ctl.beforeWrite();
System.out.println("writer1 writing:");
//WRITE OPERATION
System.out.println("done writing");
ctl.afterWrite();
}
} // end public void run()
}

class Writer2 extends Thread {
private Controller ctl;

Writer2(Controller c) { ctl = c;}

public void run()
{
while (true) {
ctl.beforeWrite();
System.out.println("writer2 writing:");
//WRITE OPERATION
System.out.println("done writing");
ctl.afterWrite();
}
} // end public void run()
}

class Controller {

private static Controller controllerInstance = null;
private int activeReaders_ = 0; // counts
private int activeWriters_ = 0;
private int waitingReaders_ = 0;


// one monitor on which all readers can wait
private Object waitingReaderMonitor_ = this;

// vector of monitors each one writer waiting on each monitor
// the size of the waiting writers vector serves as its count
private Vector waitingWriterMonitors_ = new Vector();

private Controller(){
if(controllerInstance==null)
controllerInstance = new Controller();
}


//Return an instance of Controller
protected static Controller getControllerInstance() {
return controllerInstance;
}
//allow reader if there is no active writer and no writer is waiting
private boolean allowReader() {
return activeWriters_ == 0 && waitingWriterMonitors_.size() == 0;
}

//allow writer if no other writer is already waiting and there are no active writers/readers
private boolean allowWriter() {
return waitingWriterMonitors_.size() == 0 && activeReaders_ == 0 && activeWriters_ == 0;
}

public void beforeRead() {
synchronized(waitingReaderMonitor_) {
if (allowReader()) {
++activeReaders_;
return;
}
else
++waitingReaders_;
try { waitingReaderMonitor_.wait(); }
catch (InterruptedException ex) {}
}
}

public void beforeWrite() {
Object monitor = new Object();
synchronized (monitor) {
synchronized (this) {
if (allowWriter()) {
++activeWriters_;
return;
}
waitingWriterMonitors_.addElement(monitor);
}
try { monitor.wait(); } catch (InterruptedException ex) {}
}
}

private synchronized void notifyReaders() { // waken readers
synchronized(waitingReaderMonitor_) {
waitingReaderMonitor_.notifyAll();
}
activeReaders_ = waitingReaders_; // all waiting readers now active
waitingReaders_ = 0;
}

private synchronized void notifyWriter() { // wake up 1 writer
if (waitingWriterMonitors_.size() > 0) {
Object oldest = waitingWriterMonitors_.firstElement();
waitingWriterMonitors_.removeElementAt(0);
synchronized(oldest) {
++activeWriters_;
oldest.notify();
}
}
}

public synchronized void afterRead() {
if (--activeReaders_ == 0)
notifyWriter();
}

public synchronized void afterWrite() {
--activeWriters_;
if (waitingReaders_ > 0) // prefer waiting readers
notifyReaders();
else
notifyWriter();
}
}