#include <fstream.hfa>
#include <thread.hfa>

volatile int SharedRW = 0;								// shared variable to test readers and writers

enum RW { READER, WRITER };
monitor ReadersWriter {
	int rcnt, wcnt;										// number of readers/writer using resource
	condition RWers;
};

void ?{}( ReadersWriter & rw ) with(rw) { rcnt = wcnt = 0; }
void StartRead( ReadersWriter & mutex rw ) with(rw) {
	if ( wcnt !=0 || ! is_empty( RWers ) ) wait( RWers, READER );
	rcnt += 1;
	if ( ! is_empty( RWers ) && front( RWers ) == READER ) signal( RWers );
}
void EndRead( ReadersWriter & mutex rw ) with(rw) {
	rcnt -= 1;
	if ( rcnt == 0 ) signal( RWers );
}
void StartWrite( ReadersWriter & mutex rw ) with(rw) {
	if ( wcnt != 0 || rcnt != 0 ) wait( RWers, WRITER );
	wcnt = 1;
}
void EndWrite( ReadersWriter & mutex rw ) with(rw) {
	wcnt = 0;
	signal( RWers );
}
int readers( ReadersWriter & rw ) { return rw.rcnt; }

void Read( ReadersWriter & rw ) {
	StartRead( rw );
	sout | "Reader:" | active_thread() | ", shared:" | SharedRW | " with:" | readers( rw ) | " readers";
	yield( 3 );
	EndRead( rw );
}
void Write( ReadersWriter & rw ) {
	StartWrite( rw );

	SharedRW += 1;
	sout | "Writer:" | active_thread() | ",  wrote:" | SharedRW;
	yield( 1 );
	EndWrite( rw );
}

thread Worker {
	ReadersWriter &rw;
};
void ?{}( Worker & w, ReadersWriter * rw ) { &w.rw = rw; }
void main( Worker & w ) with(w) {
	for ( 10 ) {
		if ( rand() % 100 < 70 ) {					// decide to be a reader or writer
			Read( rw );
		} else {
			Write( rw );
		} // if
	} // for
}

int main() {
	enum { MaxTask = 5 };
	ReadersWriter rw;
	Worker *workers[MaxTask];

	for ( i; MaxTask ) workers[i] = new( &rw );
	for ( i; MaxTask ) delete( workers[i] );
	sout | "successful completion";
} // main

// Local Variables: //
// tab-width: 4 //
// compile-command: "cfa -O2 RWMonitorINT.cfa" //
// End: //
