转自:Visual Studio调试器指南---多线程应用程序调试(一) - 活着的虫子 - 博客园 (cnblogs.com)
很好入门帖吗,微软那个讲多线程的帖子没看太明白,放在这里了:
微软:调试多线程应用 - Visual Studio (Windows) | Microsoft Docs
Visual Studio调试器指南---多线程应用程序调试(一)
线程是操作系统向其授予处理器时间的指令序列。 在操作系统中运行的每个进程都包含至少一个线程。 包含多个线程的进程称为多线程。有多个处理器、多核处理器或超线程进程的计算机可以同时运行多个线程。 使用多个线程的并行处理可以极大地提高程序性能,但也可能导致调试变得更加困难,因为正在跟踪多个线程。
多线程处理可能会引入新类型的潜在 bug。 例如,两个或多个线程可能需要访问同一资源,但是一次只能有一个线程可以安全地访问该资源。 需要某种形式的互斥才能确保每次只有一个线程访问该资源。 如果未正确实现互斥,则可能会创建不会执行任何线程的死锁情况。 死锁通常是一个难以调试的问题。
用于调试多线程应用的工具
Visual Studio 提供不同的工具用于调试多线程应用程序。
-
对于线程,调试线程的主要工具有 "线程" 窗口、源窗口中的线程标记、"并行堆栈" 窗口、"并行监视" 窗口和 "调试位置" 工具栏。
-
对于使用任务并行库(TPL)或并发运行时的代码,用于调试的主要工具是 "并行堆栈" 窗口、"并行监视" 窗口和 "任务" 窗口,该窗口还支持JavaScript.
-
对于调试 GPU 上的线程,主要工具是“GPU 线程”窗口。
-
对于进程,主要工具是“附加到进程”对话框、“进程”窗口和“调试位置”工具栏。
Visual Studio 还提供功能强大的断点和跟踪点,在调试多线程应用程序时,这会很有用。 使用断点条件和筛选器将断点置于单个线程上。 使用跟踪点可以在不中断的情况下跟踪程序的执行,从而研究死锁之类的问题。
调试具有用户界面的多线程应用程序可能会特别困难。 可以考虑在另一台计算机上运行应用程序并使用远程调试。
使用 "线程" 窗口调试多线程应用
多个 Visual Studio 用户界面元素可帮助调试多线程应用。 下面介绍 "代码编辑器" 窗口、"调试位置" 工具栏和 "线程" 窗口中的多线程调试功能。
“启动调试”
-
在
代码
行上设置断点,方法是单击左侧的滚动条线,或选择线条并按F9。断点在代码行旁边的左侧滚动条中显示为红色圆圈。 -
选择 "调试" > "开始调试",或按F5。
应用程序在调试模式下启动,并在断点处暂停。
-
在中断模式下,通过选择 "调试" > Windows > 线程打开 "线程" 窗口。 你必须在调试会话中才能打开或查看线程和其他调试窗口。
检查线程标记
-
"线程" 窗口中右键单击,然后选择菜单中的 "在源中 。
源代码行旁边的装订线现在显示一个线程标记图标。 线程标记指示线程在此位置停止。 如果该位置有多个已停止的线程,则会显示图标。
-
将指针悬停在线程标记上。 显示数据提示,并显示已停止的线程或线程的名称和线程 ID 号。 线程名称可能
<No Name>
。为了帮助识别不需要的线程,您可以在 "线程" 窗口中重命名它们。 右键单击该线程,然后选择 "重命名"。
-
右键单击源代码中的线程标记可查看快捷菜单上的可用选项。
标记线程和取消标记线程
您可以标记线程以跟踪您要特别注意的线程。
在源代码编辑器或 "线程" 窗口中标记和取消标记线程。 从 "调试位置" 或 "线程" 窗口工具栏中选择是仅显示标记的线程还是显示所有线程。 从任何位置进行的选择将影响所有位置。
在源代码中标记和取消标记线程
-
通过选择 "视图" > 工具栏 > 调试位置,打开 "调试位置" 工具栏。 还可以在工具栏区域中右键单击,然后选择 "调试位置"。
-
"调试位置" 工具栏有三个字段: "进程"、"线程" 和 "堆栈帧"。 下拉线程列表,并记下有多少线程。 在线程列表中,当前正在执行的线程由 > 符号标记。
-
在源代码窗口中,将鼠标悬停在滚动条中的一个线程标记图标上,并在数据提示中选择标志图标(或一个空标志图标)。 标志图标变为红色。
您还可以右键单击线程标记图标,指向 "标志",然后从快捷菜单中选择要标记的线程。
-
在 "调试位置" 工具栏上,选择 "仅显示标记的线程" 图标在 "线程" 字段的右侧。 除非标记一个或多个线程,否则图标为灰显。
只有已标记的线程才会出现在工具栏的 "线程" 下拉列表中。 若要再次显示所有线程,请再次选择 "仅显示标记的线程" 图标。
提示
标记了某些线程后,可以将光标放在代码编辑器中,右键单击,然后选择 "将标记的线程运行到光标处"。 请确保选择所有已标记的线程将达到的代码。 将标记的线程运行到光标处将暂停选定代码行上的线程,从而可以更轻松地通过冻结和解冻线程控制执行顺序。
-
若要切换当前正在执行的线程的已标记或未标记状态,请选择 "仅显示标记的线程" 按钮左侧的单个标志 "切换当前线程标记状态" 工具栏按钮。 标记当前线程对于仅显示标记的线程时查找当前线程非常有用。
-
若要取消标记线程,请将鼠标悬停在源代码中的线程标记上,并选择红色标记图标以清除它,或右键单击线程标记,然后选择 "取消标记"。
在 "线程" 窗口中标记和取消标记线程
在 "线程" 窗口中,已标记的线程旁边显示红色标志图标,而未标记的线程(如果已显示)具有空图标。
选择标记图标,以根据其当前状态将线程状态更改为标记或未标记。
还可以右键单击行,然后从快捷菜单中选择 "标记"、"取消标记" 或 "取消标记所有线程"。
"线程" 窗口工具栏还具有 "仅显示标记的线程" 按钮,它是两个标志图标中的 righthand。 它的工作方式与 "调试位置" 工具栏上的按钮相同,其中的一个按钮控制两个位置的显示。
其他线程窗口功能
在 "线程" 窗口中,选择任意列的标头以按该列对线程进行排序。 再次选择以反转排序顺序。 如果显示了所有线程,则选择标志图标列会按标记或未标记的状态对线程进行排序。
"线程" 窗口的第二列(没有标头)是当前线程列。 此列中的黄色箭头标记当前执行点。
"位置" 列显示每个线程在源代码中出现的位置。 选择Location项旁边的展开箭头,或将鼠标悬停在该项上,以显示该线程的部分调用堆栈。
有关线程调用堆栈的图形视图,请使用 "并行堆栈" 窗口。 若要在调试时打开窗口,请选择 "调试"> Windows > "并行堆栈"。
除了标记 、取消标记和取消标记所有线程外,线程窗口项的右键单击上下文菜单还具有:
- "在源中显示线程" 按钮。
- 十六进制显示,将 "线程" 窗口中的线程 ID更改为十进制格式。
- 切换到线程,这会立即将执行切换到该线程。
- 重命名,使你可以更改线程名称。
- 冻结和解冻命令。
冻结和解冻线程执行
可以冻结和解冻线程,也可以挂起和恢复线程,以控制线程执行工作的顺序。 冻结和解冻线程可帮助解决并发性问题,如死锁和争用条件。
提示
若要在不冻结其他线程的情况下跟踪单个线程,这也是一种常见的调试方案,请参阅开始调试多线程应用程序。
冻结和解冻线程:
-
在 "线程" 窗口中,右键单击任意线程,然后选择 "冻结"。 "当前线程" 列中的暂停图标指示线程已冻结。
-
选择 "线程" 窗口工具栏中的列,然后选择 "挂起的计数" 以显示 "挂起的计数" 列。 冻结线程的挂起计数值为1。
-
右键单击冻结的线程,然后选择 "解冻"。
暂停图标消失,"挂起的计数" 值更改为0。
切换到另一个线程
尝试切换到另一个线程时,可能会看到应用程序处于中断模式窗口。 此窗口告诉您该线程没有当前调试器可以显示的任何代码。 例如,你可能正在调试托管代码,但线程是本机代码。 此窗口提供了解决此问题的建议。
切换到另一个线程:
-
在 "线程" 窗口中,记下当前线程 ID (当前线程列中带有黄色箭头的线程)。 你需要切换回此线程以继续运行你的应用程序。
-
右键单击其他线程,然后从上下文菜单中选择 "切换到线程"。
-
观察 "线程" 窗口中的黄色箭头位置是否已更改。 原始的当前线程标记也保留为轮廓。
查看代码源编辑器中的线程标记上的工具提示,以及 "调试位置" 工具栏上的 "线程" 下拉列表中的列表。 观察当前线程是否也已更改。
-
在 "调试位置" 工具栏上,从 "线程" 列表中选择一个不同的线程。 请注意,当前线程还会在其他两个位置发生更改。
-
在源代码编辑器中,右键单击线程标记,指向 "切换到线程",然后从列表中选择另一个线程。 观察当前线程是否在所有三个位置发生了更改。
在源代码中,通过线程标记,只能切换到在该位置停止的线程。 使用“线程”窗口和“调试位置”工具栏可以切换到任何线程。
你现在已经了解了调试多线程应用程序的基础知识。 您可以使用 "线程" 窗口、"调试位置" 工具栏中的 "线程" 或 "源代码编辑器" 中的 "线程" 标记来观察、标记和取消标记线程,以及冻结和解冻线程。