Quantcast
Channel: 懒得折腾
Viewing all articles
Browse latest Browse all 764

Dining philosophers problem

$
0
0
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
  }
  
}



Viewing all articles
Browse latest Browse all 764

Trending Articles