Universidad de Costa Rica

Escuela de Ciencias de la Computación e Informática

CI-0122 Sistemas Operativos

Temas

CI0122 / Temas revisados / Semana-06 / Java / DP


/**
 *
 *  This solution is a Silberschatz Operating System book adaptation
 *  Simulates  a "monitor" using a Java class
 *    use a lock to control access to monitor methods
 *
 **/

import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.Condition;

/**
 * Emulates the Dining Philosophers problem
 */
public class DiningPh {

   final ReentrantLock monitor = new ReentrantLock();	// Restricts access to each public method in this class (monitor)
   final Condition[] self = new Condition[5];		// Access control to chopstick
   public enum State { Thinking, Hungry, Eating }	// Philosopher's states
   private State[] state;				// Each of the philosophers state

/**
 * Initializes all monitor variables
 **/
   public DiningPh() {
      state = new State[ 5 ];

      for ( int person = 0; person < 5; person++ ) {
         state[ person ] = State.Thinking;
         self[ person ] = monitor.newCondition();	// Creates a new condition variable associated with monitor lock
      }

   }

/*
 * Check if a philosopher can pick up his two chopsticks, if not the thread will wait
 * @param who philosopher number trying to pickup chopsticks
 */
   public void pickup( int who ) {

    state[ who ] = State.Hungry;
    monitor.lock();
    try {
       printstr( who, "will try to pickup sticks" );
       test( who );
       if ( state[ who ] == State.Hungry ) {
           printstr( who, "\tsticks are busy, will wait for them " );
           self[ who ].await();		// Chopsticks are busy, thread must wait
       }
    } catch ( InterruptedException intException ) {
    } finally {
       monitor.unlock();
    }

    printstr( who, "will start eating" );

   }

/*
 * When a philosopher ends eating, he will return chopsticks
 * With this two freed chopsticks, the thread need to check if one of their neighbors are waiting for one
 * and awake it using the test method
 * @param who philosopher number who returns its chopsticks
 */
   public void putdown( int who ) {

      monitor.lock();
      try {
         printstr( who, "end eating, will putdown sticks" );
         state[ who ] = State.Thinking;	// Change state to thinking
         test( (who + 4) % 5 );		// Check for right neighbor
         test( (who + 1) % 5 );		// Check for left heighbor
      } finally {
         monitor.unlock();
      }

   }

/*
 * Check if a philosopher can eat, verify if both chopsticks are free and self state to "Hungry"
 * @param who philosopher number checking it he can eat
 */
   private void test( int who ) {
      if ( ( state[ (who + 4) % 5 ] != State.Eating ) && 
           ( state[ who ] == State.Hungry ) && 
           ( state[ (who + 1) % 5] != State.Eating ) ) {
           state[ who ] = State.Eating;
           printstr( who, "will signal condition" );
           self[ who ].signal();
      }

   }

/*
 * Print each person status, called from within a thread
 * @param who philosopher number who want to print
 */
   public void print( int who ) {
      for ( int person = 0; person < 5; person++  ) {
          System.out.printf( "(%d) Philosopher %d is %s \n", who, person + 1, (state[person]==State.Hungry)?"Hungry":(state[person]==State.Thinking)?"Thinking":"Eating");

      }

   }

/*
 *
 */
   public void printstr( int who, String s ) {
      int person = who + 1;
      System.out.println( "Philosopher " + person + ", " + s );

   }

}