package posa import scala.actors.Actor /** * Actor representing a philosopher. * When receives message n, will eat n times and terminate. Eat sequence: * 1. picks up left chopstick (may block until available) * 2. picks up right chopstick (may block until available) * 3. eats * 4. puts down right chopstick * 5. puts down left chopstick */ class Philosopher(id: Int, leftChopstick: Int, rightChopstick: Int) extends Actor { def act() { receive { case n: Int => // Repeat the eat sequence n times for (i <- 1 to n) { while (!Dinner.pickUpChopstick(id, leftChopstick, true)) {} while (!Dinner.pickUpChopstick(id, rightChopstick, false)) {} Console.printf("Philosopher %s eats.%n", id.toString) Dinner.putDownChopstick(id, rightChopstick, false) Dinner.putDownChopstick(id, leftChopstick, true) } exit() } } } /** * Dinner of 5 philosophers, each eating 5 times. */ object Dinner extends App { // Map to print out side val side: Map[Boolean, String] = Map(true -> "Left", false -> "Right") // Array of Booleans representing chopsticks, true means they are on the table val chopsticks: Array[Boolean] = Array.fill(5)(true) // List of Philosopher actors, and their respective chopsticks val philosophers: List[Philosopher] = List( new Philosopher(1, 0, 1), new Philosopher(2, 1, 2), new Philosopher(3, 2, 3), new Philosopher(4, 3, 4), new Philosopher(5, 4, 0) ) // Let the feast begin philosophers.foreach(_.start) Console.println("Dinner is starting!") philosophers.foreach(_ ! 5) while (philosophers.exists(_.getState != Actor.State.Terminated)) {} Console.println("Dinner is over!") /** * Synchronized method, attempting to pick up a given chopstick by a philosopher. * Returns true if the chopstick was available and picked up successfully. * In order to prevent deadlocks, left hand side chopsticks can only be picked up if there are at least 2 chopsticks on the table. * Right hand side chopsticks can be picked up as long as they are on the table (philosophers always pick up left chopstick first). * The synchronization is the JVM native implementation of the Monitor Object pattern. * In this case the monitor of the Dinner object is used, ensuring that only one chopstick can be picked up at a time. */ def pickUpChopstick(philosopher: Int, chopstick: Int, isLeft: Boolean): Boolean = synchronized { val result = chopsticks(chopstick) && (!isLeft || chopsticks.count(c => c) > 1) if (result) { Console.printf("Philosopher %s picks up %s chopstick.%n", philosopher.toString, side(isLeft)) chopsticks(chopstick) = false; } result } /** * Puts down the given chopstick by a philosopher. * No synchronization is needed. */ def putDownChopstick(philosopher: Int, chopstick: Int, isLeft: Boolean) = { Console.printf("Philosopher %s puts down %s chopstick.%n", philosopher.toString, side(isLeft)) chopsticks(chopstick) = true } }
↧
Dining philosophers problem
↧