语言

在 Visual Studio 中调试多线程应用程序

线程是作系统向其授予处理器时间的指令序列。 在作系统中运行的每个进程都至少包含一个线程。 具有多个线程的进程称为多线程。

具有多个处理器、多核处理器或超线程进程的计算机可以运行多个同时线程。 使用多个线程的并行处理可以极大地提高程序性能,但也可能使调试更加困难,因为你正在跟踪多个线程。

完美的并行处理并不总是可能的。 有时必须同步线程。 一个线程可能需要等待另一个线程的结果,或者一个线程可能需要对另一个线程正在使用的资源进行独占访问。 同步问题是多线程应用程序中 bug 的常见原因。 有时线程最终可能会等待永远不会变得可用的资源。 这会导致名为 死锁的条件。

线程和进程

线程 和 进程 是计算机科学的相关概念。 两者都表示必须按特定顺序执行的指令序列。 但是,单独的线程或进程中的说明可以并行执行。

作系统中存在进程,对应于用户视为程序或应用程序的内容。 另一方面,线程存在于进程中。 因此,线程有时称为 轻型进程。 每个进程由一个或多个线程组成。

存在多个进程可使计算机一次执行多个任务。 存在多个线程使进程能够并行执行工作。 在具有多处理器的计算机上,进程或线程可以在不同的处理器上运行。 这可实现真正的并行处理。

用于调试多线程应用的工具

Visual Studio 提供了用于调试多线程应用的不同工具。

  • 对于 GPU 上的调试线程,主工具是 “GPU 线程” 窗口。 请参阅 “如何:使用 GPU 线程”窗口。

  • 对于进程,主要工具是“ 附加到进程 ”对话框、 “进程 ”窗口和 “调试位置” 工具栏。

Visual Studio 还提供强大的断点和跟踪点,这在调试多线程应用程序时非常有用。 使用断点条件和筛选器在单个线程上放置断点。 利用跟踪点,可以跟踪程序的执行而不中断,以研究死锁等问题。 有关详细信息,请参阅 断点作和跟踪点。

调试具有用户界面的多线程应用程序可能特别困难。 可以考虑在第二台计算机上运行应用程序并使用远程调试。 有关详细信息,请参阅 远程调试。

下表显示了可用信息,以及可在以下每个位置执行的作:

用户界面 可用信息 可以执行的作
“附加到进程 ”对话框 可附加到的可用进程:

- 进程名称(.exe)
- 进程 ID 号
- 菜单栏标题
- 类型(托管 v4.0;托管 v2.0、v1.1、v1.0;x86;x64;IA64)
- 用户名(帐户名)
- 会话编号
选择要附加到的进程

选择远程计算机

更改连接到远程计算机的传输类型
“进程” 窗口 附加的进程:

- 进程名称
- 进程 ID 号
- 处理 .exe 的路径
- 菜单栏标题
- 状态 (中断。正在运行)
- 调试(本机、托管等)。
- 传输类型(默认,本机无身份验证)
- 传输限定符 (远程计算机)
工具:

-附加
-分离
-终止

快捷菜单:

-附加
-分离
- 调试停止时分离
-终止
调试位置 工具栏 - 当前进程
- 暂停应用程序
- 恢复应用程序
- 暂停和关闭应用程序
- 当前线程
- 切换当前线程标志状态
- 仅显示已标记的线程
- 仅显示当前进程
- 当前堆栈帧
- 切换到另一个进程
- 暂停、恢复或关闭应用程序
- 切换到当前进程中的另一个线程
- 切换到当前线程中的另一个堆栈帧
- 标记或取消标记当前线程
- 仅显示已标记的线程
- 仅显示当前进程
“并行堆栈” 窗口 - 一个窗口中多个线程的调用堆栈。
- 每个线程的活动堆栈帧。
- 任何方法的调用方和被调用方。
- 死锁检测
- 筛选掉指定的线程
- 筛选出外部代码堆栈
- 切换到“任务”视图
- 标记或取消标记线程
-缩放
- 复制堆栈帧
- 将所有堆栈保存/导出为图像
“并行监视 ”窗口 - 标志列,可在其中标记要特别注意的线程。
- 框架列,其中箭头指示所选框架。
- 可显示计算机、进程、磁贴、任务和线程的可配置列。
- 标记或取消标记线程
- 仅显示已标记的线程
- 切换帧
- 对列进行排序
- 对线程进行分组
- 冻结或解冻线程
- 在“并行监视”窗口中导出数据
“线程” 窗口 当前进程中的线程:

- 线程 ID
- 托管 ID
- 类别(主线程、接口线程、远程过程调用处理程序或工作线程)
- 线程名称
- 创建线程的位置
-优先权
- 相关性掩码
- 挂起计数
- 进程名称
- 标志指示器
- 挂起的指示器
工具:

-搜索
- 搜索调用堆栈
- 标记仅我的代码
- 标记自定义模块选择
- 分组依据
-列
- 展开/折叠调用堆栈
- 展开/折叠组
- 冻结/解冻线程

快捷菜单:

- 在源中显示线程
- 切换到线程
- 冻结正在运行的线程
- 解冻冻结线程
- 标记线程以供其他研究
- 取消标记线程
- 重命名线程
- 显示和隐藏线程

其他作:

- 查看 DataTip 中线程的调用堆栈
源窗口 左侧装订线中的线程指示器指示单个或多个线程(默认情况下关闭,在 “线程” 窗口中使用快捷菜单打开) 快捷菜单:

- 切换到线程
- 标记线程以供其他研究
- 取消标记线程
“任务” 窗口 - 查看有关 Task 对象的信息,包括任务 ID、任务状态(计划、正在运行、等待、死锁),以及分配给任务的线程。
- 调用堆栈中的当前位置。
- 在创建时传递给任务的委托
- 切换到当前任务
- 标记或取消标记任务
- 冻结或解冻任务
GPU 线程 窗口 - 标志列,可在其中标记要特别注意的线程。
- 当前线程列,其中黄色箭头指示当前线程。
- “ 线程计数 ”列,该列显示同一位置的线程数。
- “行 ”列,显示每个线程组所在的代码行。
- “地址 ”列,其中显示每个线程组所在的指令地址。
- “位置” 列,它是地址代码中的位置。
- 状态 列,显示线程是活动还是被阻止。
- 磁贴 列,显示行中线程的磁贴索引。
- 更改为其他线程
- 显示特定的磁贴和线程
- 显示或隐藏列
- 按列排序
- 对线程进行分组
- 冻结或解冻线程
- 标记或取消标记线程
- 仅显示已标记的线程