“跨过"在 Visual Studio 中调试多线程程序时

在 Visual Studio(在我的例子中是 2005)中调试程序时让我烦恼的一件事是,当我使用step over"(通过按 F10)执行到下一行代码时,我经常最终在与我正在查看的线程完全不同的线程中到达特定的代码行.这意味着我正在做的事情的所有上下文都丢失了.

我该如何解决这个问题?

如果这可以在更高版本的 Visual Studio 中实现,我也想了解一下.

在下一行代码上设置一个断点,它有条件只为这个线程中断不是我正在寻找的答案,因为它对我来说太有用了:)

解决方案

我认为您的问题只有一个答案,您认为这是工作量太大".但是,我相信这是因为您以错误的方式进行操作.让我介绍在线程 ID 上添加条件断点的步骤,这些步骤非常简单,但在您了解它们之前并不明显.

  1. 在您要继续调试的正确线程中停止调试器(我猜这通常是到达那里的第一个线程).

  2. 在监视窗口中输入 $TID.

  3. 添加一个断点,条件为$TID == <观察窗口中$TID的值>
    示例:$TID == 0x000016a0

  4. 继续执行.

$TID 是 Microsoft 编译器(至少从 Visual Studio 2003 起)的魔术变量,具有当前线程 ID 的值.它比查看 (FS+0x18)[0x24] 容易得多.=D

话虽如此,您可以使用一些简单的宏获得与调试器的 One-Shot 断点相同的行为.当您跳过时,调试器在后台设置一个断点,运行到该断点,然后将其删除.保持用户界面一致的关键是在遇到任何断点时删除这些断点.

以下两个宏为当前线程提供Step Over 和Run To Cursor.这是以与调试器相同的方式完成的,执行后断点将被删除,无论命中哪个断点.

您需要分配一个组合键来运行它们.

<块引用>

注意:一个警告――Step Over 宏只有在光标位于您想要跳过的行上时才能正常工作.这是因为它通过光标位置确定当前位置,并简单地将行号加一.您也许可以用当前执行点的信息替换位置计算,但我无法从宏 IDE 中找到该信息.

他们来了,祝你好运!

<块引用>

要在 Visual Studio 中使用这些宏:
1. 打开宏 IDE(从菜单中选择:Tools->Macros->Macro IDE...)
2. 添加一个新的代码文件(从菜单中:选择:Project->Add New Item...,选择Code File,然后点击Addem> )
3. 粘贴此代码.
4. 保存文件.

添加组合键以在 Visual Studio 中运行这些宏:
1. 打开选项(从菜单中选择:工具->选项)
2. 展开到Environment->Keyboard
3. 在 Show commands contains: 中,输入 Macros. 以查看您的所有宏.
4. 选择一个宏,然后点击按快捷键:
5. 输入您要使用的组合(退格键删除输入的组合)
6. 点击Assign设置运行所选宏的快捷方式.

导入系统进口 EnvDTE进口 EnvDTE80导入系统.诊断公共模块 DebugHelperFunctions子 RunToCursorInMyThread()Dim textSelection As EnvDTE.TextSelection将 myThread 调暗为 EnvDTE.ThreadDim bp As EnvDTE.BreakpointDim bps As EnvDTE.Breakpoints' 对于 Breakpoints.Add()将文件名变暗为字符串Dim LineNumber 作为整数Dim ThreadID 作为字符串' 获取本地参考以方便使用myThread = DTE.Debugger.CurrentThreadtextSelection = DTE.ActiveDocument.SelectionLineNumber = textSelection.ActivePoint.Line文件名 = textSelection.DTE.ActiveDocument.FullName线程ID = myThread.ID' 在当前文件的当前行中为当前线程添加一个一次性"断点bps = DTE.Debugger.Breakpoints.Add("", FileName, LineNumber, 1, "$TID == " & ThreadID)'跑到下一站DTE.Debugger.Go(真)' 删除我们的一次性"断点对于每个 bp 在 bpsbp.Delete()下一个结束子子 StepOverInMyThread()Dim textSelection As EnvDTE.TextSelection将 myThread 调暗为 EnvDTE.ThreadDim bp As EnvDTE.BreakpointDim bps As EnvDTE.Breakpoints' 对于 Breakpoints.Add()将文件名变暗为字符串Dim LineNumber 作为整数Dim ThreadID 作为字符串' 获取本地参考以方便使用myThread = DTE.Debugger.CurrentThreadtextSelection = DTE.ActiveDocument.SelectionLineNumber = textSelection.ActivePoint.Line文件名 = textSelection.DTE.ActiveDocument.FullName线程ID = myThread.ID行号 = 行号 + 1' 在当前文件的当前行中为当前线程添加一个一次性"断点bps = DTE.Debugger.Breakpoints.Add("", FileName, LineNumber, 1, "$TID == " & ThreadID)'跑到下一站DTE.Debugger.Go(真)' 删除我们的一次性"断点对于每个 bp 在 bpsbp.Delete()下一个结束子终端模块

<块引用>

免责声明:我在 Visual Studio 2005 中编写了这些宏.您可能可以在 Visual Studio 2008 中很好地使用它们.它们可能需要针对 Visual Studio 2003 及更早版本进行修改.

One thing that annoys me when debugging programs in Visual Studio (2005 in my case) is that when I use "step over" (by pressing F10) to execute to the next line of code, I often end up reaching that particular line of code in a totally different thread than the one I was looking at. This means that all the context of what I was doing was lost.

How do I work around this?

If this is possible to do in later versions of Visual Studio, I'd like to hear about it as well.

Setting a breakpoint on the next line of code which has a conditional to only break for this thread is not the answer I'm looking for since it is way too much work to be useful for me :)

解决方案

I think there is only one answer to your question, which you have discounted as being 'way too much work.' However, I believe that is because you are going about it the wrong way. Let me present steps for adding a conditional breakpoint on Thread ID, which are extremely easy, but not obvious until you know them.

  1. Stop the debugger at a point where you are in the correct thread you want to continue debugging in (which I would guess is usually the first thread that gets there).

  2. Enter $TID into the watch window.

  3. Add a break point with the condition $TID == <value of $TID from Watch Window>,
    Example: $TID == 0x000016a0

  4. Continue Execution.

$TID is a magic variable for Microsoft compilers (since at least Visual Studio 2003) that has the value of the current Thread ID. It makes it much easier than looking at (FS+0x18)[0x24]. =D

That being said, you can get the same behavior as the debugger's One-Shot breakpoints with some simple macros. When you step over, the debugger, behind the scenes, sets a breakpoint, runs to that breakpoint and then removes it. The key to a consistent user interface is removing those breakpoints if ANY breakpoint is hit.

The following two macros provide Step Over and Run To Cursor for the current thread. This is accomplished in the same manner as the debugger, with the breakpoints being removed after execution, regardless of which breakpoint is hit.

You will want to assign a key combination to run them.

NOTE: One caveat -- The Step Over macro only works correctly if the cursor is on the line you want to step over. This is because it determines the current location by the cursor location, and simply adds one to the line number. You may be able to replace the location calculation with information on the current execution point, though I was unable to locate that information from the Macro IDE.

Here they are and good luck bug hunting!!

To use these macros in Visual Studio:
1. Open the Macro IDE ( from the Menu, select: Tools->Macros->Macro IDE... )
2. Add a new Code File ( from the Menu: select: Project->Add New Item..., choose Code File, and click Add )
3. Paste in this code.
4. Save the file.

To add key combinations for running these macros in Visual Studio:
1. Open Options (from the Menu, select: Tools->Options )
2. Expand to Environment->Keyboard
3. In Show commands containing:, type Macros. to see all your macros.
4. Select a macro, then click in Press shortcut keys:
5. Type the combo you want to use (backspace deletes typed combos)
6. click Assign to set your shortcut to run the selected macro.

Imports System
Imports EnvDTE
Imports EnvDTE80
Imports System.Diagnostics

Public Module DebugHelperFunctions

    Sub RunToCursorInMyThread()
        Dim textSelection As EnvDTE.TextSelection
        Dim myThread As EnvDTE.Thread
        Dim bp As EnvDTE.Breakpoint
        Dim bps As EnvDTE.Breakpoints

        ' For Breakpoints.Add()
        Dim FileName As String
        Dim LineNumber As Integer
        Dim ThreadID As String

        ' Get local references for ease of use 
        myThread = DTE.Debugger.CurrentThread
        textSelection = DTE.ActiveDocument.Selection

        LineNumber = textSelection.ActivePoint.Line
        FileName = textSelection.DTE.ActiveDocument.FullName
        ThreadID = myThread.ID

        ' Add a "One-Shot" Breakpoint in current file on current line for current thread
        bps = DTE.Debugger.Breakpoints.Add("", FileName, LineNumber, 1, "$TID == " & ThreadID)

        ' Run to the next stop
        DTE.Debugger.Go(True)

        ' Remove our "One-Shot" Breakpoint
        For Each bp In bps
            bp.Delete()
        Next
    End Sub

    Sub StepOverInMyThread()
        Dim textSelection As EnvDTE.TextSelection
        Dim myThread As EnvDTE.Thread
        Dim bp As EnvDTE.Breakpoint
        Dim bps As EnvDTE.Breakpoints

        ' For Breakpoints.Add()
        Dim FileName As String
        Dim LineNumber As Integer
        Dim ThreadID As String

        ' Get local references for ease of use 
        myThread = DTE.Debugger.CurrentThread
        textSelection = DTE.ActiveDocument.Selection

        LineNumber = textSelection.ActivePoint.Line
        FileName = textSelection.DTE.ActiveDocument.FullName
        ThreadID = myThread.ID
        LineNumber = LineNumber + 1

        ' Add a "One-Shot" Breakpoint in current file on current line for current thread
        bps = DTE.Debugger.Breakpoints.Add("", FileName, LineNumber, 1, "$TID == " & ThreadID)

        ' Run to the next stop
        DTE.Debugger.Go(True)

        ' Remove our "One-Shot" Breakpoint
        For Each bp In bps
            bp.Delete()
        Next
    End Sub


End Module

Disclaimer: I wrote these macros in Visual Studio 2005. You can probably use them fine in Visual Studio 2008. They may require modification for Visual Studio 2003 and before.

相关文章