Looks like many people liked my macros that made multithreaded debugging easier. One of the comments on the article from Sam was worth exploring deeper:
John,
Great post!
Would you have any idea how to make VS do this: http://stackoverflow.com/questions/837869/is-there-a-shortcut-in-vs-for-next-statement-in-current-thread
This very common problem comes up the more threads you have. The gist of the problem is that you’re stepping one thread, but all of a sudden, you’re stepping a completely different thread. What’s happening is that the thread your stepping is getting it’s time slice, but your other threads are not so the thread scheduler pulls the thread you’re stepping off the CPU and puts a starving thread on. Hence, it looks like you are bouncing around threads.
The solution proposed in the Stack Overflow question is to freeze the other threads, which is about all you can do. Once stopped in the debugger, open the Threads window and right click on the thread you don’t want to run and select Freeze from the context menu.
In the above screen shot, I already froze thread ID 5788, which is shown by the pause icon in the far left column and the Suspend column has a count of 1. Note that the suspend count could be higher if your code has called Thread.Suspend/SuspendThread on the thread. If you want to freeze multiple threads from the debugger at the same time, hold down the control key and click to multi select. The context menu Freeze works on all selected threads.
That’s great that you can freeze threads like this. However, could you possibly screw up your application doing so? Absolutely! If you’re doing mixed .NET and native debugging and you suspend the garbage collector thread, let’s just say your garbage collections might take approximately forever to finish. Freezing threads is a very powerful technique, but one to use carefully. Many times all you want to do is ensure you step through the end of the current function without bouncing to another thread so freezing all the other threads probably won’t cause any problems as long as you thaw them before you return.
If you have only two threads in your application, it’s easy to freeze the other thread. It gets more tedious if you have many threads in your application. (If you think you have a bunch now, wait until we are all using the new Parallel Task Library coming up in .NET 4.0.) When I’m debugging and want to freeze threads, I always seem to be suspending all the other threads in the program except the active one. As I’m too lazy to manually select all those other threads, I automated thread freezing and thawing with the FreezeAllButActiveThread and ThawAllFrozenThread macros below for your enjoyment. Note that the Threads window sometimes doesn’t update after running these macros to show the new state.
Is there anything else you want to see automated while debugging? How about with Visual Studio itself? If so, ask away in the comments or send me an email. Consider me your personal developer! <grin>
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Wintellect Debugging Code
' Copyright © 1997-2009 John Robbins -- All rights reserved.
' Freeze and thaw threads in bulk.
'
' Version 1.0 - July 17, 2009
' - Initial version.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Imports System
Imports EnvDTE
Imports EnvDTE80
Imports EnvDTE90
Imports System.Diagnostics
Imports System.Text
Imports System.Collections.Generic
Imports System.Runtime.InteropServices
Imports System.Windows.Forms
Public Module FreezeThawThreads
Public Sub FreezeAllButActiveThread()
Dim dbg As EnvDTE90.Debugger3 = DTE.Debugger
If dbg.CurrentMode = dbgDebugMode.dbgBreakMode Then
Dim currProg As Program = dbg.CurrentProgram
For Each t As Thread2 In currProg.Threads
If (t.ID <> dbg.CurrentThread.ID) Then
If t.IsFrozen = False Then
t.Freeze()
End If
End If
Next
Else
NotInBreakMode()
End If
End Sub
Public Sub ThawAllFrozenThreads()
Dim dbg As EnvDTE90.Debugger3 = DTE.Debugger
If dbg.CurrentMode = dbgDebugMode.dbgBreakMode Then
Dim currProg As Program = dbg.CurrentProgram
For Each t As Thread2 In currProg.Threads
If t.IsFrozen = True Then
t.Thaw()
End If
Next
Else
NotInBreakMode()
End If
End Sub
Private Sub NotInBreakMode()
MessageBox.Show(New MainWindow(), _
"You must be stopped in the debugger for this macro to work", _
"Wintellect Thread Freeze/Thaw Macros", _
MessageBoxButtons.OK, _
MessageBoxIcon. Error)
End Sub
' A helper class so I can parent message boxes correctly on the IDE.
Class MainWindow
Implements IWin32Window
Public ReadOnly Property Handle() _
As System.IntPtr Implements IWin32Window.Handle
Get
' The HWnd property is undocumented.
Dim ret As IntPtr = CType(DTE.MainWindow.HWnd, IntPtr)
Return (ret)
End Get
End Property
End Class
End Module