This tutorial demonstrates using Thread Validator to monitor an application before and after part of the application deadlocks. The techniques in this tutorial are demonstrated using two threads for ease of understanding. However, the techniques are applicable to any number of threads.
Note that for your executing nativeExample your critical section addresses, thread Ids and sequence numbers will all be different. We have used the values that we experienced to write this tutorial. Substitute your own values where appropriate.
Using the Per Thread Locks tab, right click on the entry for each deadlocked critical section. A context menu will be displayed.
Choose Information about lock/wait…. A modeless dialog containing information about the lock is displayed.
For the example shown above, the information is most readily acquired from the Per Thread Locks tab. The information is:
Thread Id | Critical Section | Sequence | Locked |
---|---|---|---|
342 | 0x002195fc | 18193 | Locked |
342 | 0x002195d8 | 18194 | Waiting |
340 | 0x002195fc | 18197 | Waiting |
340 | 0x002195d8 | 18194 | Locked |
Sorting this by sequence ID and lock status (where Locked has priority over Waiting when sequence IDs are identical), we get:
Thread Id | Critical Section | Sequence | Locked |
---|---|---|---|
342 | 0x002195fc | 18193 | Locked |
340 | 0x002195d8 | 18194 | Locked |
342 | 0x002195d8 | 18194 | Waiting |
340 | 0x002195fc | 18197 | Waiting |
The above table can be displayed by choosing the Display Lock Order entry on the Query menu. An example is shown below:
This information demonstrates that the locks were acquired in one order in Thread 340 and a different order in thread 342. Good multi-threading requires that locks are acquired in the same order. This is the cause of the deadlock. One of the threads needs to be modified to acquire the locks in the same order as the other thread.
We can see from the Owning Module column the source code location – however in this case it is in an MFC inline header file (afxmt.inl) which indicates the code is inside a CCriticalSection object. This is not very useful information for identifying which code called the Lock() method on the critical section object. We require a callstack for this method call.
Using the Per Thread Locks tab, right click on the entry for each deadlocked critical section. A context menu will be displayed. Choose Show Callstack…. A modeless dialog displays the callstack for the lock. Expanding the callstack allows you to drill down to the source code. As you can see from the image, this thread is acquiring the locks in the order sect1_a, sect2_a.
Inspecting the source code for the other thread will show the order the locks were acquired for that thread. As you can see from the image below the data in the table above is correct – the locks are acquired in a different order to the first thread – resulting in deadlock.