在Visual Studio中调试多线程程序时“跳过”

时间:2008-12-03 09:32:12

标签: c++ visual-studio multithreading debugging visual-studio-2005

在Visual Studio(我的情况下是2005)中调试程序时,有一件事让我感到恼火的是,当我使用“跳过”(通过按 F10 )执行到下一行代码时,我经常最终在一个与我正在看的完全不同的线程中达到特定代码行。这意味着我所做的所有背景都已丢失。

我该如何解决这个问题?

如果可以在Visual Studio的更高版本中执行此操作,我也想听听它。

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

6 个答案:

答案 0 :(得分:39)

我认为你的问题只有一个答案,你已经打折为“太多工作”。但是,我认为这是因为你的方式错误。让我介绍在线程ID上添加条件断点的步骤,这些步骤非常简单,但在您了解它们之前并不明显。

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

  2. 在观察窗口中输入$TID

  3. 从观察窗 $TID == <添加条件> 值$ TID的断点,示例$TID == 0x000016a0

  4. 继续执行。

  5. $TID是Microsoft编译器的一个神奇变量(因为至少Visual Studio 2003)具有当前线程ID的值。它比查看(FS + 0x18)[0x24]更容易。 = d

    话虽这么说,你可以使用一些简单的宏获得与调试器的One-Shot断点相同的行为。当您跳过时,调试器在后台设置断点,运行到该断点然后将其删除。如果 ANY 断点被击中,则一致用户界面的关键是删除这些断点。

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

    您需要指定一个组合键才能运行它们。

      

    注意 :一个警告 - 如果光标位于您要跳过的行上, Step Over 宏只能正常工作。这是因为它通过光标位置确定当前位置,只需在行号中添加一个。您可以使用当前执行点的信息替换位置计算,但我无法从宏IDE中找到该信息。

    在这里,他们是好运虫狩猎!!

      

    在Visual Studio中使用这些宏:
      1.打开宏IDE(从菜单中选择:工具 - &gt;宏 - >宏IDE ...
      2.添加新的代码文件(从菜单中选择:项目 - >添加新项目... ,选择代码文件,然后单击添加< / em>)
      3.粘贴此代码。
      4.保存文件。

         

    添加用于在Visual Studio中运行这些宏的组合键:
      1.打开选项(从菜单中选择:工具 - >选项
      2.展开到环境 - >键盘
      3.在显示包含以下内容的命令中,键入 宏。 以查看所有宏。
      4.选择一个宏,然后单击按快捷键:
      5.键入要使用的组合(退格键删除键入的组合
      6.单击分配以设置运行所选宏的快捷方式。

    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
    
      

    免责声明:我在 Visual Studio 2005 中编写了这些宏。你可以在 Visual Studio 2008 中使用它们。他们可能需要修改 Visual Studio 2003 以及之前。

答案 1 :(得分:21)

您可以使用“线程”调试窗口冻结另一个线程或切换到另一个线程( Ctrl + Alt + H )。

答案 2 :(得分:6)

调试一个特定线程的简单方法是从Threads窗口冻结所有其他线程。

答案 3 :(得分:2)

[Ctrl + D,T]或[Ctrl + Alt + H] - 打开线程窗口(用于监控,冻结和命名线程)

线程窗口允许您选择是否要在visual studio中显示其他线程的位置。这是一个很好的提醒我,我正在调试的当前线程并不是唯一正在运行的线程。将鼠标悬停在线程标记上会获得线程名称和ID。

更多提示发现于:http://devpinoy.org/blogs/jakelite/archive/2009/01/10/5-tips-on-debugging-multi-threaded-code-in-visual-studio-net.aspx

答案 4 :(得分:2)

显然,当调试器必须在该线程中断之前或者如果设置了将在此线程中命中的断点时,如果按 F10 ,Visual Studio 2010将仅切换到其他线程。

我使用以下代码来测试行为:

class Program
{
    static void Main(string[] args)
    {
        var t = new Thread(new ThreadStart(Work));
        t.Start();

        for (int i = 0; i < 20; i++)
        {
            Thread.Sleep(1000);
            Console.WriteLine("............");
        }

        t.Join();
    }

    static void Work()
    {
        for (int i = 0; i < 20; i++)
        {
            Thread.Sleep(1000);
            Console.WriteLine("ZZzzzzzzzzzzzzzz");
        }
    }
}

如果你只是踩到程序或在Main()方法中添加一个断点,点击 F10 只会逐步完成主线程中的代码。

如果在Work()方法中添加断点,则调试器将逐步执行两个线程。

Visual Studio的这种行为是有道理的,但这对我来说似乎都是一个没有记录的功能......

答案 5 :(得分:1)

我最近遇到了同样调试某个线程的问题。虽然我不打算将上述答案视为非常全面和有价值的(并希望我在2天前找到它) - 但我实施了以下内容以帮助&#34;每天&#34;故障排除。

在多个线程中运行同一个类的多个实例时,这个想法只是一个简单的解决方法 - 我们的应用程序一直在这样做。

我们使用唯一ID或名称初始化所有类实例,因此我们知道实例的创建方式或原因。然后,当我们需要调试特定实例(即线程) - 而不是冻结其他线程时,我们添加以下内容:

if (instance.ID == myID)
{
    // Assert BreakPoint
}

在我们的情况下,我们会建立固定ID,因此我们知道在遇到问题时我们要解决的ID。