ThreadMentor: Visualizing Alarm Clock

Compile and run the program for a short moment, and you will see the following History Graph window:

This window shows a sequence of events that happened in the beginning of the program. There are six sleeper threads, SleeperThread1 to SleeperThread6, and a driver thread DriverThread. From the history bars, we learn that sleeper thread SleeperThread1 enters the monitor and then waits as indicated by the CW (i.e., condition wait) tag. This permits the next thread, SleeperThread2, to enter the monitor. This process repeats until all six sleeper threads enter the monitor and wait. Then, the driver thread DriverThread enters. However, the driver thread does not wait. It wakes up a sleeper. This signal causes two events to happen: (1) the driver thread becomes inactive (i.e., the CY tag) because this is a Hoare monitor, and (2) one sleeper thread is released from the condition variable (i.e., the CA tag of thread SleeperThread1). This sleeper thread wakes up the next sleeper thread and becomes inactive. The History Graph window shows that thread SleeperThread2 is the current active thread in the monitor.

The main window (below left) records this fact. It shows that thread SleeperThread2 is active in monitor AlarmClock. Six threads are in the monitor (i.e., sleeper threads 1 and 3 to 6, and the driver thread) and no thread is waiting to enter. To learn the details, check the Monitor window (below right). We see that sleeper threads 3 to 6 are blocked by condition variable Wake, and threads SleeperThread1 and DriverThread are inactive. Thread DriverThread (resp., SleeperThread1) is inactive because it signaled thread SleeperThread1 (resp., SleeperThread2) and yielded the monitor.

The above windows depict the entering monitor and waiting cycle. If the program runs for a little longer, we shall see the wake-up cycle. The following is the History Graph window. The first tag pair (i.e., CY and CA) appeared near the end of the previous History Graph window. When thread DriverThread signals condition variable Wake, thread SleeperThread1 is released, which, in turn, signals condition variable Wake, causing thread SleeperThread2 to be released. This chain reaction continues, until thread SleeperThread6 is released. It signals condition variable Wake. However, since all threads have been released, this signal is lost and thread SleeperThread6 yields the monitor. Meanwhile, all sleeper threads are inactive because they all executed a condition variable signal. Consequently, the driver thread is reactivated (i.e., the MR tag) and then exits (i.e., the ME tag). This causes the monitor to become empty, and, as a result, one of the inactive sleeper threads re-enters and becomes active. The history bar shows that thread SleeperThread1 is the active one, because there is a MR tag on its history bar. After exits the monitor, the driver thread comes back to send in the next clock tick (i.e., the MB tag).

The main window (below left) tells the same story. There are five threads in the monitor and one thread waiting to enter. The active thread is SleeperThread1. The details are shown in the Monitor window (below right). Now we know the thread that is waiting to enter is the driver thread (we also learn this from the History Graph window. Of these 5 threads that are in the monitor, thread SleeperThread6 waits on condition variable Wake, and the other four sleeper threads are inactive (i.e., re-enter).

This process repeats. Later, we will see a sleeper that has slept for sufficient number of clock ticks exiting the monitor. After a while, it will come back for the next round.