Question

I have been working on the philosopher dinning task and I have a problem, my code revolves around 3 classes, Forks, philosophers and dinerTable (yes I named the last two with small letters by mistake).

The code starts properly, philosopher 0 and 2 grab their forks, but then the code just stops, can anyone help me please?

There are the 3 classes :

Forks (extends Thread) :

public synchronized boolean isFree() throws InterruptedException
{
    return available;

}

public synchronized void returnFork() throws InterruptedException
{
    available = true;
    this.notify();
}

public synchronized void takeFork() throws InterruptedException
{
    available = false;
    this.notify();
}

philosophers (implements Runnable) :

    private int number;
private Forks right;
private Forks left;
private boolean hasBothForks;
private boolean keepGoing;

public boolean isKeepGoing() {
    return keepGoing;
}

public void setKeepGoing(boolean keepGoing) {
    this.keepGoing = keepGoing;
}

public philosophers(int number,Forks right, Forks left, boolean keepGoing)
{
    this.number = number;
    this.right = right;
    this.left = left;
    hasBothForks = false;
    this.keepGoing = keepGoing;
}

private void print(String message)
{
    System.out.println("Philosopher " + number + " " + message );

}

@Override
public void run() {
    if(keepGoing == true)
    {
        try
        {


            print("is hungry");
            print( "checks if forks are free");
            if(right.isFree() == true && left.isFree() == true && hasBothForks == false)
            {
                print("is grabbing forks");
                right.takeFork();
                left.takeFork();
                hasBothForks = true;
            } // end if
            else if(hasBothForks == true)
            {
                print("is eating");
                Thread.sleep(2000);
                print("is putting down left fork");
                left.returnFork();
                print("is putting down right fork");
                right.returnFork();
                print("is finished eating");
                hasBothForks = false;
            } // end if
            else if(right.isFree() == false && left.isFree() == false && hasBothForks == false)
                {
                    print("is thinking");
                    Thread.sleep(2000);
                } // end if             

        } // end try
        catch (InterruptedException e) {

                    print(" is interrupted");

        } // end catch
    } // end if


} // end run

dinerTable :

private static int num = 5;
private static Forks right = null;
private static Forks left = null;
private static Forks[] forks = new Forks[num];
private static philosophers[] philosophers = new philosophers[num];

public static void main(String args[])
{
    for (int i = 0; i < num ; i++)
    {
        forks[i] = new Forks();
    }
        for (int i = 0; i < num; i++)
        {
            if (i > 0)
            {
                left = forks[i - 1];
                right = forks[i];
            } // end if
            else if ( i == 0)
            {
                left = forks[num-1];
                right = forks[i];
            } // end if

            philosophers[i] = new philosophers(i, right, left, true);

            Thread thread = new Thread(philosophers[i]);
            thread.start();

        } // end for

        System.out.print("\n");
}
Was it helpful?

Solution 2

After changing the if to a while in the run method of philosopher, try updating the Forks functions for take and return as follows:

public synchronized void returnFork() throws InterruptedException
{
    available = true;
    this.notifyAll();
}

public synchronized void takeFork() throws InterruptedException
{
    while(!available){
      this.wait();
    }
    available = false;
}

I then made a couple of tweaks in the run method of philosophers as follows:

      if (!hasBothForks){
        print("is hungry");
        print( "checks if forks are free");            
      }

      if(right.isFree() == true && left.isFree() == true && hasBothForks == false)
      {
          print("is grabbing forks");
          right.takeFork();
          left.takeFork();
          hasBothForks = true;
      } // end if
      else if(hasBothForks == true)
      {
          print("is eating");
          Thread.sleep(2000);
          print("is putting down left fork");
          left.returnFork();
          print("is putting down right fork");
          right.returnFork();
          print("is finished eating");
          hasBothForks = false;
      } // end if
      else if((right.isFree() == false || left.isFree() == false) && hasBothForks == false)
          {
              print("is thinking");
              Thread.sleep(2000);
          } // end if 

With these two sets of changes I see the output flow much better. Still not sure if it's exactly what you want though.

OTHER TIPS

I am posting this an answer as I cannot post comments.

The initial problem with this is that there is no thread synchronisation. it is possible for ALL of the philosophers to obtain both forks because of a race condition.

if(right.isFree() == true && left.isFree() == true && hasBothForks == false)
{
    print("is grabbing forks");
    right.takeFork();
    left.takeFork();
    hasBothForks = true;
}

if it happens in this order:

P1: right.isFree() == true, left.isFree() == true, hasBothForks == false - thread is slept by the scheduler
P2: right.isFree() == true, left.isFree() == true, hasBothForks == false - thread is slept by the scheduler
P3: right.isFree() == true, left.isFree() == true, hasBothForks == false - thread is slept by the scheduler
P4: right.isFree() == true, left.isFree() == true, hasBothForks == false - thread is slept by the scheduler
P5: right.isFree() == true, left.isFree() == true, hasBothForks == false - thread is slept by the scheduler

P1: right.takeFork(), left.takeFork() - thread is slept by the scheduler
P2: right.takeFork(), left.takeFork() - thread is slept by the scheduler
P3: right.takeFork(), left.takeFork() - thread is slept by the scheduler
P4: right.takeFork(), left.takeFork() - thread is slept by the scheduler
P5: right.takeFork(), left.takeFork() - thread is slept by the scheduler

EDIT:

The solution to this threading problem is two fold.

Firstly the fork are actually meant to be a thread safe object known as a Mutex or Semaphore. This means that only 1 token is available per fork and the other people requesting this fork must wait until it is available.

Secondly you need a way for the philosophers to not all go for the left fork first, or all go for the right fork first as this can cause starvation. Instead you need to come up with a solution such as making odd numbered philosophers be left handed (grab left fork first) and even number philosophers right handed (grab right fork first).

With these two issues fixed you should always have at least 1 philosopher who is able to be eating, and once he is finished eating releases both Forks (read semaphores) and allows other philosophers to acquire the forks.

EDIT 2:

A good in depth explanation of the solution I suggested is available at: http://www.cs.mtu.edu/~shene/NSF-3/e-Book/MUTEX/TM-example-left-right.html

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top