ThreadMentor: Visualizing Dining Philosophers: The Lefty-Righty Version

Basics

Run the program with four lefty philosophers and one righty philosopher for a while. The following are screen-shots of the Thread Status window and History Graph window. We see that threads Lefty1, Lefty2, Lefty3, Righty5 are blocked and thread Lefty4 is running. This is understandable because thread Righty5 is a righty. More precisely, after threads Lefty1, Lefty2, Lefty3 and Lefty4 have acquired the mutex locks for their left chopsticks (i.e., chopsticks 0, 1, 2, and 3), thread Righty5 cannot lock his right chopstick (i.e., chopstick 0) because it is owned by thread Lefty1. As a result, chopstick 4 is free, and thread Lefty4 gets it and starts eating. This is the reason that only thread Lefty4 is running.

To verify this, click on the Mutex button in the upper-right corner of the main window to display all existing mutex locks in the display area (left figure below). Then, we see that mutex lock ChopStick0 is locked by thread Lefty1 and has one thread waiting, while mutex locks ChopStick3 and ChopStick4 are owned by thread Lefty4. This means that thread Lefty4 has both chopsticks and is eating. If you look at the display area carefully, you do not see thread Righty5, because it is waiting for his right chopstick (i.e., chopstick 0) which is current owned by thread Lefty1. Note also that mutex lock ChopStick4 has no waiting thread because it is the left chopstick of the righty thread Righty5 that is waiting for his right chopstick on mutex lock ChopStick0! To check this, click on the line that contains mutex lock ChopStick0 to bring up its window (right figure below). We learn that this lock is currently owned by thread Lefty1 and has thread Righty5 waiting. Therefore, the above explanation is justified. You can bring up a source window by clicking on the MW tag of thread Righty5's history bar to see the lock acquisition call. Hence, this tells us that these windows can help us trace and visualize the activities of mutex locks.

Visualizing the Lock-Unlock Connections

Clicking on the Mutex Locks button of the History Graph window displays the connection between MU (lock release) and ML (lock acquisition) tags. The following screen-shot is taken after the program runs a little longer.

As shown by the history bars, threads Lefty1, Lefty3, Lefty4 and Righty5 are blocked and thread Lefty2 is running. Let us analyze this situation. Consider thread Lefty4. The first two pairs of MW and ML tags help thread Lefty4 get his two chopsticks. Then, Lefty4 runs for a brief time and releases its first chopstick (i.e., chopstick 3) that is needed by thread Lefty3. Meanwhile thread Lefty3 has its left chopstick (i.e., chopstick 2) and is waiting for his right chopstick (i.e., chopstick 3). Thus, the release of chopstick 3 by Lefty4 causes thread Lefty3 to pick it up, and, hence, Lefty3's history bar has a ML tag. After this point, thread Lefty3 is running.

Return to thread Lefty4. After releases its left chopstick, it releases its right chopstick (i.e., chopstick 4). However, this MU has no connection line! Why? This is because chopstick 4 is the left chopstick of the righty philosopher Righty5 who is still waiting for his right chopstick (i.e., chopstick 0) that is being held by thread Lefty1. Then, thread Lefty4 runs for some time (i.e., thinking) and goes back to get his left chopstick. Thread Lefty4 cannot get it immediately and hence a MW tag is shown. Meanwhile thread Lefty3 has both chopsticks and is eating. After a while, thread Lefty3 finishes eating and releases his chopsticks. The release of thread Lefty3's left chopstick causes thread Lefty2 to pick it up and eat, and the release of the second chopstick makes thread Lefty4 to have its left chopstick. Therefore, we see a connection between a MU tag of thread Lefty3 and a ML tag of thread Lefty2, and a connection between a MU tag of thread Lefty3 and a ML tag of thread Lefty4.

In this way, with the help of your source program (or the source window), the History Graph and the Mutex windows, you can easily reconstruct all the activities of your program, even though it is a multithreaded one. If your program have screen output as all of sample programs do, it is even easier because you can match the activities statement-by-statement.