Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4517307

(thread) DiningPhilosophers test hung - Thread.activeCount == 2 at program start

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Duplicate
    • Icon: P4 P4
    • None
    • 1.4.0
    • core-libs
    • sparc
    • solaris_8

      Name: fh87463 Date: 10/19/2001



      Test DiningPhilosophers test hung when running with merlin JDK after(include) build 70
      on solsparc/solx86/linux platform. It will pass when running with ladybird and merline
      JDK before build 69.

      All source file and tonga log located under:
      /net/jano.sfbay/export/disk20/GammaBase/Bugs/[BugID]

      To reproduce the bug:
      =====================
      1. cd /net/jano.sfbay/export/disk20/GammaBase/Bugs/[BugID]
      2. go into one of the sub directory
      3. run *tlog file.

      Here is java source code:

      /******************************************************************************

                      DiningPhilosophers.java
           
                      This class tests Thread synchronization by means of a classic
              Operating Systems problem called Dining Philosophers.

                      Description of Analogy:
                      A given number of Philosophers spend their lives thinking and
              eating around a large table with a bowl of rice in the middle. Each
              Philosopher eats with chopsticks - and the Philosophers must share
              their chopsticks. In the classic scenario, each Philosopher has one
              chopstick on his/her right and one chopstick on his/her left.
              Because we are dealing with a finite machine, and not a theoretical
              structure, I've decided to fix the number of chopsticks to two. There
              may be one hundred Philosophers. They all have to share one pair of
              chopsticks. I did this because I wanted to see how well the system keeps
              track of things when there are a lot of Threads waiting by means of
      synchronization.
                      In both the classic scenario and my own, a Philosopher must have both
              chopsticks in order to eat.


                      Implementation :
                      The number of Philosophers who share the two chopsticks is given
              as a command-line argument. The program reads the String in, converts it
              to an integer value, and then uses that value to determine the number of
              Philosophers to create.
                      Here, I've decided to implement Philosophers as Threads, each of
      which have to use both Chopsticks to eat a certain number of "turns".
      The actual "Chopsticks" are not implemented as variables in the program.
      Instead, to keep everything simpler, I decided to use two boolean arrays,
      "left_chopstick_used" and "right_chopstick_used" for the Philosopher Threads
      to synchronize on. Both arrays are two-dimensional, with the first dimension
      corresponding to the number of concurrent Philosopher Threads, and the second
      dimension corresponding to the number of times that Philosopher has eaten.
      Every time a Philosopher gains the monitor for one of
      these arrays, the Philosopher is said to have grabbed a Chopstick.
      Each time a Philosopher Thread gains the monitor for an array, it sets
      the value of that array at that index to "true."
      Every time a Philosopher Thread gains both Chopsticks, that Philosopher
      eats. To represent this, I used a one-dimensional boolean array - "has_eaten"
      with a number of entries equal to the number of Philosopher Threads times the
      number of turns each Philosopher takes. Each time a Philosopher eats, he
      sets the value of one of the indices in "has_eaten" to "true." He also
      increments the static int index of that "has_eaten" array. The name of this
      static int index is "has_eaten_index" - I am not endeavoring to be terribly
      imaginative with names here!!
      Note that neither the "has_eaten" array nor its static "has_eaten_index"
      have any kind of synchronization code around them. This apparently dangerous
      omission has a practical application: only one Philosopher Thread at a time
      gets access to both Chopsticks, and therefore only one Philosopher Thread
      at a time gets access to the "has_eaten" array, and can only increment its index
      in an appropriate fashion if the synchronization code is working according to
      the specifications. If the synchronization code does not exclude other
      Philosopher Threads, the chances are overwhelming that the public static
      int "has_eaten_index" will be incremented in an inappropriate manner, and
      therefore the test will fail.
      At the very end of the test, after all the Philosopher Threads have
      run and died, the "main" goes through all the arrays, checking their boolean
      values. if it finds one of these values set to "false", it will exit
      with status = 1 (FAIL). If the exit(1) conditions don't trigger, the
      test is assumed to have passed, and the message "TEST PASSED" is printed
      out for the reader.


      *****************************************************************************/



      import java.lang.*;
      import java.io.*;

      /*
      "DiningPhilosophers" class

      This public class contains the main() which gets everything going
      and contains all the public arrays and variables which it checks at the end.

      */

      public class DiningPhilosophers{

      public static boolean[][] used_left_chopstick;
      public static boolean[][] used_right_chopstick;
      public static boolean[] has_eaten;
      public static int has_eaten_index = 0;
      public static int NUMBER_OF_PHILOS;//determined from command-line argument
      public static final int NUMBER_OF_TURNS = 100000;//constant - we want it big

      public static void main(String argv[]){

      NUMBER_OF_PHILOS = Integer.parseInt(argv[0]);
                  

      used_left_chopstick = new boolean[NUMBER_OF_PHILOS][NUMBER_OF_TURNS];
      used_right_chopstick = new boolean[NUMBER_OF_PHILOS][NUMBER_OF_TURNS];
      has_eaten = new boolean[NUMBER_OF_PHILOS*NUMBER_OF_TURNS];


      //initialize - if any Thread skips one of these, we want it to fail
      for(int i=0; i<NUMBER_OF_PHILOS; i++){
      for(int j=0; j<NUMBER_OF_TURNS; j++){
      used_left_chopstick[i][j] = false;
      used_right_chopstick[i][j] = false;
      has_eaten[i*j+j] = false;
      }//end inner for
      }//end outer for

      for(int i=1; i<=NUMBER_OF_PHILOS; i++){
      new Philosopher(i).start();
      }//end for

      //wait until all Philosopher Threads have finished.
      while (Thread.activeCount()>1)
      Thread.currentThread().yield();

      //now, we check all three boolean arrays for any values remaining at "false"
      for(int i=0; i<NUMBER_OF_PHILOS; i++){
      for(int j=0; j<NUMBER_OF_TURNS; j++){
      if(! used_left_chopstick[i][j])
      System.exit(1);
      if(! used_right_chopstick[i][j])
      System.exit(1);
      if(! has_eaten[i*j+j])
      System.exit(1);
      }//end inner for
      }//end outer for

      //if we got to this point, the test passed
      System.out.println("TEST PASSED");

      }//end main

      }//end public class DiningPhilosophers


      /*
      "Philosopher" class

      This class extends Thread, so it can run like a Thread. It
      uses synchronization to ensure exclusive access to the "has_eaten" boolean
      array and its "has_eaten_index"

      */

      class Philosopher extends Thread{

      private int index;

      //constructor
      public Philosopher(int index){
      super(String.valueOf(index));
      this.index = index;
      }//end constructor

      public void run(){

      for(int steps=0; steps < DiningPhilosophers.NUMBER_OF_TURNS; steps++){
      synchronized(DiningPhilosophers.used_left_chopstick){
      DiningPhilosophers.used_left_chopstick[index-1][steps] = true;
      synchronized(DiningPhilosophers.used_right_chopstick){
      DiningPhilosophers.used_right_chopstick[index-1][steps] = true;
      DiningPhilosophers.has_eaten[DiningPhilosophers.has_eaten_index++] = true;
      }//end synchronized - DiningPhilosophers.used_right_chopstick
      }//end synchronized - used_left_chopstick
      }//end for

      }//end public void run() method

      }//end non-public Philosopher class



      ======================================================================

            psoper Pete Soper (Inactive)
            fhsusunw Francis Hsu (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: