在调试Visual Studio(我使用的是2005版本)程序时,有一件事情经常让我感到烦恼,就是当我使用“步过”(通过按下 F10 键)执行到下一行代码时,我经常会到达完全不同于我所在线程的那一行代码。这意味着我正在做的所有上下文信息都丢失了。
我该如何解决这个问题?
如果在较新版本的Visual Studio中可以做到这一点,我也想了解一下。
设置一个在下一行代码上具有条件断点以仅在此线程中断的方法不是我要寻找的答案,因为它需要太多的工作量,对我来说没有什么用处 :)
在调试Visual Studio(我使用的是2005版本)程序时,有一件事情经常让我感到烦恼,就是当我使用“步过”(通过按下 F10 键)执行到下一行代码时,我经常会到达完全不同于我所在线程的那一行代码。这意味着我正在做的所有上下文信息都丢失了。
我该如何解决这个问题?
如果在较新版本的Visual Studio中可以做到这一点,我也想了解一下。
设置一个在下一行代码上具有条件断点以仅在此线程中断的方法不是我要寻找的答案,因为它需要太多的工作量,对我来说没有什么用处 :)
我认为你的问题只有一个答案,但你认为这个方法需要做的工作太多。不过,我认为这是因为你的方法不对。让我给你介绍一下如何添加条件断点到Thread ID的步骤,这些步骤非常简单,但在你了解它们之前并不明显。
在你想要继续调试的正确线程中停止调试器(我猜通常是第一个到达的线程)。
在监视窗口输入$TID
。
添加带条件的断点$TID == <
从监视窗口获得的$TID值>
,
例如: $TID == 0x000016a0
继续执行。
$TID
是Microsoft编译器(至少从Visual Studio 2003开始)的神奇变量,它具有当前线程ID的值。与查看(FS+0x18)[0x24]相比,它使事情容易多了。 =D
话虽如此,您可以通过一些简单的宏获得与调试器的单次断点相同的行为。当你单步执行时,调试器在幕后设置一个断点,运行到该断点,然后删除它。保持一致用户界面的关键是如果击中任何断点,则删除这些断点。
以下两个宏为当前线程提供了Step Over和Run To Cursor。这是通过与调试器相同的方式完成的,即在执行后删除断点,无论哪个断点被击中。
您将想要为它们分配一个键组合来运行它们。
注意:一个警告--Step Over宏只有在光标位于您想要跨越的行上时才能正常工作。这是因为它通过光标位置确定当前位置,然后将行号加1。您可以尝试使用有关当前执行点的信息替换位置计算,但我无法从宏IDE中找到该信息。
下面是这些宏,祝你捉虫好运!
在Visual Studio中使用这些宏:
1.打开宏IDE(从菜单中选择:Tools->Macros->Macro IDE...)
2.添加新的代码文件(从菜单中选择:Project->Add New Item...,选择Code File,然后单击Add)
3.粘贴这段代码。
4.保存文件。在Visual Studio中为运行这些宏添加键盘组合:
1.打开选项(从菜单中选择:Tools->Options)
2.展开到Environment->Keyboard
3.在Show commands containing:中输入Macros.以查看您的所有宏。
4.选择一个宏,然后点击Press shortcut keys:中
5.键入您想要使用的组合(backspace删除已键入的组合)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及其之前,可能需要进行修改。
调试特定线程的简单方法是从“线程”窗口冻结所有其他线程。
显然,只有在调试器之前必须中断该线程或设置了将在此线程中触发的断点时,Visual Studio 2010才会切换到其他线程,如果您按下F10。
我使用以下代码来测试这种行为:
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 的这种行为是有意义的,但对我来说似乎都是未记录的功能......
最近我遇到了只调试特定线程的问题。虽然我不会否认上面的答案非常全面和有价值(希望我两天前就找到它了)- 但我实施了以下方法来帮助“日常”故障排除。
这个想法只是在多个线程中运行相同类的多个实例时的一个简单解决方法 - 这是我们的应用程序一直在做的。
我们使用唯一的ID或名称初始化所有类实例,以便知道实例是如何或为什么创建的。然后,当我们需要调试特定实例(即线程) - 而不是冻结其他线程时,我们添加以下内容:
if (instance.ID == myID)
{
// Assert BreakPoint
}
$tid
伪变量仅在调试本机代码时可用。来源:https://msdn.microsoft.com/zh-cn/library/ms164891.aspx - Keith Morgan