summaryrefslogtreecommitdiff
path: root/sources/examples/pilib/rwlock.scala
diff options
context:
space:
mode:
authorcremet <cremet@epfl.ch>2003-08-26 15:28:51 +0000
committercremet <cremet@epfl.ch>2003-08-26 15:28:51 +0000
commit80d3a625a75ba054eef58eac94dc3a8066690c36 (patch)
treeccdc5d3d86415b7630666961d2741589cf59dede /sources/examples/pilib/rwlock.scala
parent4c10e8515b2d1b7991f660b444f4b0a5d014286d (diff)
downloadscala-80d3a625a75ba054eef58eac94dc3a8066690c36.tar.gz
scala-80d3a625a75ba054eef58eac94dc3a8066690c36.tar.bz2
scala-80d3a625a75ba054eef58eac94dc3a8066690c36.zip
- Added "PiLib" library and associated examples.
- Fixed some files in the package "scala.concurrent".
Diffstat (limited to 'sources/examples/pilib/rwlock.scala')
-rw-r--r--sources/examples/pilib/rwlock.scala328
1 files changed, 328 insertions, 0 deletions
diff --git a/sources/examples/pilib/rwlock.scala b/sources/examples/pilib/rwlock.scala
new file mode 100644
index 0000000000..65578ea51b
--- /dev/null
+++ b/sources/examples/pilib/rwlock.scala
@@ -0,0 +1,328 @@
+/**
+* From Pi to Scala: Semaphores, monitors, read/write locks.
+* Readers/writers locks.
+*/
+object rwlock {
+
+ import scala.concurrent.pilib._;
+
+ class Signal extends Chan[unit] {
+ def send = write(());
+ def receive = read;
+ }
+
+ class CountLock {
+ private val busy = new Signal;
+ def get = busy.send;
+ def release = busy.receive;
+ spawn < release >
+ }
+
+ /** A binary semaphore
+ */
+ class Lock {
+ private val busy = new Signal;
+ private val free = new Signal;
+ def get = busy.send;
+ def release = free.send;
+ spawn < (while (true) {
+ choice (
+ busy * (x => free.receive),
+ free * (x => ())
+ )
+ })
+ >
+ }
+
+ /** A monitor a la Java
+ */
+ class JavaMonitor {
+
+ private val lock = new Lock;
+
+ private var waiting: List[Signal] = Nil;
+
+ def synchronized[a](def s: a): a = {
+ lock.get; val result = s; lock.release; result
+ }
+
+ def Wait = {
+ val s = new Signal;
+ waiting = s :: waiting;
+ lock.release;
+ s.receive;
+ lock.get;
+ }
+
+ def Notify = {
+ if (!waiting.isEmpty) {
+ waiting.head.send;
+ waiting = waiting.tail;
+ }
+ }
+
+ def NotifyAll = {
+ while (!waiting.isEmpty) {
+ waiting.head.send;
+ waiting = waiting.tail;
+ }
+ }
+
+ def await(def cond: boolean): unit = while (false == cond) (Wait)
+ }
+
+ /*
+ class Buffer[a](size: Int) extends JavaMonitor with {
+ var in = 0, out = 0, n = 0;
+ val elems = new Array[a](size);
+ def put(x: a) = synchronized {
+ await(n < size);
+ elems(out) = x;
+ out = (out + 1) % size;
+ }
+ def get: a = synchronized {
+ await(n > 0);
+ val x = elems(in);
+ in = (in + 1) % size;
+ x
+ }
+ }
+ */
+
+ /** A readers/writers lock. */
+ trait ReadWriteLock {
+ def startRead: unit;
+ def startWrite: unit;
+ def endRead: unit;
+ def endWrite: unit;
+ }
+
+ /**
+ * A readers/writers lock, using monitor abstractions.
+ */
+ class ReadWriteLock1 extends JavaMonitor with ReadWriteLock {
+
+ private var nactive: int = 0;
+ private var nwriters: int = 0;
+
+ def status =
+ System.out.println(nactive + " active, " + nwriters + " writers");
+
+ def startRead = synchronized {
+ await(nwriters == 0);
+ nactive = nactive + 1;
+ status
+ }
+
+ def startWrite = synchronized {
+ nwriters = nwriters + 1;
+ await(nactive == 0);
+ nactive = 1;
+ status
+ }
+
+ def endRead = synchronized {
+ nactive = nactive - 1;
+ if (nactive == 0) NotifyAll;
+ status
+ }
+
+ def endWrite = synchronized {
+ nwriters = nwriters - 1;
+ nactive = 0;
+ NotifyAll;
+ status
+ }
+ }
+
+ /** A readers/writers lock, using semaphores
+ */
+ class ReadWriteLock2 extends ReadWriteLock {
+
+ private var rc: int = 0; // reading readers
+ private var wc: int = 0; // writing writers
+ private var rwc: int = 0; // waiting readers
+ private var wwc: int = 0; // waiting writers
+ private val mutex = new Lock;
+ private val rsem = new Lock;
+ private val wsem = new Lock;
+
+ def startRead = {
+ mutex.get;
+ if (wwc > 0 || wc > 0) {
+ rwc = rwc + 1;
+ mutex.release;
+ rsem.get;
+ rwc = rwc - 1;
+ }
+ rc = rc + 1;
+ if (rwc > 0) rsem.release;
+ mutex.release
+ }
+
+ def startWrite = {
+ mutex.get;
+ if (rc > 0 || wc > 0) {
+ wwc = wwc + 1;
+ mutex.release;
+ wsem.get;
+ wwc = wwc - 1;
+ }
+ wc = wc + 1;
+ mutex.release;
+ }
+
+ def endRead = {
+ mutex.get;
+ rc = rc - 1;
+ if (rc == 0 && wwc > 0) wsem.release;
+ mutex.release
+ }
+
+ def endWrite = {
+ mutex.get;
+ wc = wc - 1;
+ if (rwc > 0)
+ rsem.release
+ else if (wwc > 0) wsem.release;
+ mutex.release
+ }
+ }
+
+ /** A readers/writers lock, using channels, without priortities
+ */
+ class ReadWriteLock3 extends ReadWriteLock {
+
+ private val sr = new Signal;
+ private val er = new Signal;
+ private val sw = new Signal;
+ private val ew = new Signal;
+
+ def startRead = sr.send;
+ def startWrite = sw.send;
+ def endRead = er.send;
+ def endWrite = ew.send;
+
+ private def rwlock: unit = choice (
+ sr * (x => reading(1)),
+ sw * (x => { ew.receive; rwlock })
+ );
+
+ private def reading(n: int): unit = choice (
+ sr * (x => reading(n+1)),
+ er * (x => if (n == 1) rwlock else reading(n-1))
+ );
+
+ spawn < rwlock >;
+ }
+
+ /** Same, with sequencing
+ */
+ class ReadWriteLock4 extends ReadWriteLock {
+
+ private val rwlock = new ReadWriteLock3;
+
+ private val sr = new Signal;
+ private val ww = new Signal;
+ private val sw = new Signal;
+
+ def startRead = sr.send;
+ def startWrite = { ww.send; sw.send; }
+ def endRead = rwlock.endRead;
+ def endWrite = rwlock.endWrite;
+
+ private def queue: unit = choice (
+ sr * (x => { rwlock.startRead ; queue }),
+ ww * (x => { rwlock.startWrite; sw.receive; queue })
+ );
+
+ spawn < queue >;
+ }
+
+ /** Readwritelock where writers always have priority over readers
+ */
+ class ReadWriteLock5 extends ReadWriteLock {
+
+ private val sr = new Signal;
+ private val er = new Signal;
+ private val ww = new Signal;
+ private val sw = new Signal;
+ private val ew = new Signal;
+
+ def startRead = sr.send;
+ def startWrite = { ww.send; sw.send; }
+ def endRead = er.send;
+ def endWrite = ew.send;
+
+ private def Reading(nr: int, nw: int): unit =
+ if (nr == 0 && nw == 0)
+ choice (
+ sr * (x => Reading(1, 0)),
+ ww * (x => Reading(0, 1))
+ )
+ else if (nr == 0 && nw != 0) {
+ sw.receive;
+ Writing(nw);
+ }
+ else if (nr != 0 && nw == 0)
+ choice (
+ sr * (x => Reading(nr + 1, 0)),
+ er * (x => Reading(nr - 1, 0)),
+ ww * (x => Reading(nr, 1))
+ )
+ else if (nr != 0 && nw != 0)
+ choice (
+ ww * (x => Reading(nr, nw + 1)),
+ er * (x => Reading(nr - 1, nw))
+ );
+
+ private def Writing(nw: int): unit = choice (
+ ew * (x => Reading(0, nw - 1)),
+ ww * (x => Writing(nw + 1))
+ );
+
+ spawn < Reading(0, 0) >;
+
+ }
+
+ /**
+ * Main function.
+ */
+ def main(args: Array[String]): unit = {
+ val random = new java.util.Random();
+
+ def reader(i: int, rwlock: ReadWriteLock): unit = {
+ Thread.sleep(1 + random.nextInt(100));
+ System.err.println("Reader " + i + " wants to read.");
+ rwlock.startRead;
+ System.err.println("Reader " + i + " is reading.");
+ Thread.sleep(1 + random.nextInt(100));
+ rwlock.endRead;
+ System.err.println("Reader " + i + " has read.");
+ reader(i, rwlock)
+ }
+
+ def writer(i: int, rwlock: ReadWriteLock): unit = {
+ Thread.sleep(1 + random.nextInt(100));
+ System.err.println("Writer " + i + " wants to write.");
+ rwlock.startWrite;
+ System.err.println("Writer " + i + " is writing.");
+ Thread.sleep(1 + random.nextInt(100));
+ rwlock.endWrite;
+ System.err.println("Writer " + i + " has written.");
+ writer(i, rwlock)
+ }
+
+ val rwlock = args(0) match {
+ case "1" => new ReadWriteLock1
+ case "2" => new ReadWriteLock2
+ case "3" => new ReadWriteLock3
+ case "4" => new ReadWriteLock4
+ case "5" => new ReadWriteLock5
+ }
+ List.range(0, 5) foreach (i => spawn < reader(i, rwlock) >);
+ List.range(0, 5) foreach (i => spawn < writer(i, rwlock) >);
+ }
+
+}
+