ThreadMentor: Visualizing Dining Philosophers

Basics

Run this program for a short period of time, and you will see the following thread status and history bars:

These two screens show that the main thread has not yet reached the joining point; however, all five philosopher threads have been created. At this moment, thread Philosopher3 is running, and threads Philosopher0, Philosopher1, Philosopher2 and Philosopher4 are blocked. The last tag on their history bars are MW, which means they are trying to lock a mutex lock.

Let us study thread Philosopher2 further. According to its history bar, it tried to lock a mutex at the very beginning but was not successful. Thus, it waited for a while until the mutex lock is available. Then, it locks this mutex as shown by the first two tags MW and ML. After tag ML, its history bar is shown in green, which means the thread is running. At this moment, thread Philosopher2 has successfully acquired the first lock (i.e., mutex ChopStick2 and is on the way to acquire the second lock. However, the second lock acquisition is unsuccessful and the thread is forced to wait. This is the reason that the last segment of thread Philosopher2's history bar is shown in red. To justify this analysis, you can click on the second MW tag to bring up the source window as shown below. The second call to method Lock() is highlighted!

The Details

Now, let us see how to get the details of the mutex locks. Click on the Mutex button in the main window. This will display all mutex locks that are created so far as shown below. The display area shows that mutex lock ChopStick0 is currently owned by thread Philosopher0 and has no thread waiting, while mutex ChopStick2 is currently owned by thread Philosopher2 and has one thread waiting. Mutex ChopStick4 is currently owned by no thread and has one thread waiting? Is it right? If you go back to check the History Graph window, you should see that thread Philosopher4 is trying to lock his first lock, which is ChopStick4. Once this lock acquisition is successful, the owner of ChopStick4 becomes Philosopher4 and the waiting thread count becomes zero.

If you look at the history bar of thread Philosopher1, you should see that this thread has acquired the first lock (i.e., ChopStick1) and is trying to get the second (i.e., ChopStick2). However, since ChopStick2 has already been acquired by thread Philosopher2, thread Philosopher1 must wait on mutex lock ChopStick2. To see this, click on the line in the display area that contains mutex lock ChopStick2. This will bring up a Mutex window whose name is the name of the mutex lock. Thus, you will see a window with name ChopStick2 as shown below. In this window, it is clear that the owner is thread Philosopher2 and the only waiting thread is Philosopher1.

Deadlock

We mentioned earlier that this solution could cause deadlock. Once a deadlock occurs, some or all involved threads will be blocked, and, as a result, the history bars of these threads will be shown in red. Therefore, if you see a number of history bars shown in red for a long period of time without changing color, it is a sign of deadlock. Alternatively, you can also see the same with the Thread Status window. If you run this program further, you may have the following Thread Status window and History Graph window. As you can see, the main thread is joining, and all five philosopher threads are blocked. Thus, we have a deadlock!

If you bring up all mutex lock windows as shown below, you will see a circular waiting.

From these windows we can construct the following table, which clearly shows the chain of waiting.

Thread Own Waiting for
Philosopher0 ChopStick0 ChopStick1
Philosopher1 ChopStick1 ChopStick2
Philosopher2 ChopStick2 ChopStick3
Philosopher3 ChopStick3 ChopStick4
Philosopher4 ChopStick4 ChopStick0