visual-studio 在 Visual Studio 中调试多线程程序时“跳过”
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 
原文地址: http://stackoverflow.com/questions/336628/
Warning: these are provided under cc-by-sa 4.0 license.  You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
"Step over" when debugging multithreaded programs in Visual Studio
提问by Laserallan
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.
在 Visual Studio 中调试程序(在我的例子中为 2005)时让我烦恼的一件事是,当我使用“单步F10执行”(通过按)执行到下一行代码时,我经常最终到达该特定代码行与我正在查看的线程完全不同的线程。这意味着我所做的所有上下文都丢失了。
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.
如果这可以在更高版本的 Visual Studio 中实现,我也想了解一下。
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 :)
在下一行代码上设置断点,该断点有条件只为该线程中断不是我正在寻找的答案,因为它对我有用的工作太多了:)
回答by Aaron
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.
我认为您的问题只有一个答案,您认为这是“工作太多了”。但是,我相信这是因为您以错误的方式进行操作。让我介绍在线程 ID 上添加条件断点的步骤,这些步骤非常简单,但在您了解它们之前并不明显。
- 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). 
- Enter - $TIDinto the watch window.
- Add a break point with the condition - $TID == <value of $TID from Watch Window- >,
 Example:- $TID == 0x000016a0
- Continue Execution. 
- 在您要继续调试的正确线程中停止调试器(我猜这通常是到达那里的第一个线程)。 
- 进入 - $TID观察窗口。
- $TID == <从 Watch Window添加一个条件值为 $TID的断点- >,
 示例:- $TID == 0x000016a0
- 继续执行。 
$TIDis 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
$TID是 Microsoft 编译器(至少从 Visual Studio 2003 起)的魔术变量,它具有当前线程 ID 的值。它比查看 (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 ANYbreakpoint is hit.
话虽如此,您可以使用一些简单的宏获得与调试器的 One-Shot 断点相同的行为。当您跳过时,调试器在后台设置一个断点,运行到该断点,然后将其删除。一致的用户界面的关键是在遇到任何断点时删除这些断点。
The following two macros provide Step Overand Run To Cursorfor 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.
以下两个宏为当前线程提供了Step Over和Run To Cursor。这是以与调试器相同的方式完成的,执行后将删除断点,无论命中哪个断点。
You will want to assign a key combination to run them.
您需要分配一个组合键来运行它们。
NOTE: One caveat -- The Step Overmacro 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.
注意:一个警告 -只有当光标位于您想要跳过的行上时,Step Over宏才能正常工作。这是因为它通过光标位置确定当前位置,并简单地将行号加一。您可以用当前执行点的信息替换位置计算,但我无法从宏 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 Assignto set your shortcut to run the selected macro.
要在 Visual Studio 中使用这些宏:
1. 打开宏 IDE(从菜单中选择:工具->宏->宏 IDE...)
2. 添加一个新的代码文件(从菜单中:选择:项目-> Add New Item...,选择Code File,然后单击Add)
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
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 2003and before.
免责声明:我在Visual Studio 2005 中编写了这些宏。您可能可以在Visual Studio 2008 中很好地使用它们。它们可能需要针对Visual Studio 2003及更早版本进行修改。
回答by Evgeny Lazin
You can freeze a different thread or switch to another thread using the Threads debug window (Ctrl+ Alt+ H).
您可以冻结不同的线程或使用线程调试窗口(切换到另一个线程Ctrl+ Alt+ H)。
回答by Arnon Axelrod
The simple way to debug one particular thread is to freeze all other threads from the Threads window.
调试一个特定线程的简单方法是在“线程”窗口中冻结所有其他线程。
回答by AnthonyVO
[Ctrl+D, T] or [Ctrl+Alt+H] - Opens the Thread Window (used to monitor, freeze and name threads)
[Ctrl+D, T] 或 [Ctrl+Alt+H] - 打开线程窗口(用于监控、冻结和命名线程)
The thread window allows you to select if you want to show the location of the other threads in visual studio. That is a good reminder to me that the current thread I am debugging is not the only one in play. Hovering over the thread marker gets you the threads name and id.
线程窗口允许您选择是否要在 Visual Studio 中显示其他线程的位置。这对我来说是一个很好的提醒,我正在调试的当前线程并不是唯一一个在运行的线程。将鼠标悬停在线程标记上可以获得线程名称和 ID。
More tips found at: http://devpinoy.org/blogs/jakelite/archive/2009/01/10/5-tips-on-debugging-multi-threaded-code-in-visual-studio-net.aspx
更多提示见:http: //devpinoy.org/blogs/jakelite/archive/2009/01/10/5-tips-on-debugging-multi-threaded-code-in-visual-studio-net.aspx
回答by helb
Apparently, Visual Studio 2010 only switches to other threads if you press F10when the debugger had to break in that thread before or if a breakpoint is set which will be hit in this thread.
显然,Visual Studio 2010 仅F10在调试器之前必须中断该线程时按下或设置了将在该线程中命中的断点时才切换到其他线程。
I used the following code to test the behavior:
我使用以下代码来测试行为:
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");
        }
    }
}
If you just stept to the program or add a breakpoint in the Main()method, hitting F10only steps through the code from the main thread.
如果您只是单步执行程序或在Main()方法中添加断点,则F10只能从主线程执行单步执行代码。
If you add a breakpoint in the Work()method, the debugger steps through both threads.
如果在Work()方法中添加断点,调试器将逐步执行两个线程。
This behavior of Visual Studio makes sense but it all seems like an undocumented feature to me...
Visual Studio 的这种行为是有道理的,但对我来说这似乎是一个未记录的功能......
回答by knightgambit
I recently had the same problem of debugging only a certain thread. While I won't discount the above answer as very comprehensive and valuable (and wish I had found it 2 days ago) - I implemented the following to help "everyday" troubleshooting.
我最近遇到了同样的问题,只能调试某个线程。虽然我不会认为上述答案非常全面和有价值(并希望我在 2 天前找到它) - 我实施了以下内容来帮助“日常”故障排除。
This idea is only a simple workaround when running multiple instances of the same class in multiple threads - which our application is doing at all times.
当在多个线程中运行同一类的多个实例时,这个想法只是一个简单的解决方法——我们的应用程序一直在这样做。
We initialize all class instances with a unique ID or Name, so we know how or why the instance was created. Then, when we need to debug a specific instance (i.e. thread) - and not freeze other threads, we add the following:
我们使用唯一的 ID 或名称初始化所有类实例,因此我们知道创建实例的方式或原因。然后,当我们需要调试特定实例(即线程)而不冻结其他线程时,我们添加以下内容:
if (instance.ID == myID)
{
    // Assert BreakPoint
}
In our case, we establish fixed ID's, so we know the ID we want to troubleshoot when we have an issue.
在我们的例子中,我们建立了固定的 ID,所以当我们遇到问题时,我们知道我们想要解决的 ID。

