C#和vs2008中的线程调试

5
我有一个相当严重的多线程调试问题。我在与串行设备交互时遇到了某种时间问题,需要追踪它。我有三个线程:
1. 用于 UI 更新的主线程。用户可以通过选择预设来一次性更改设备的一个或多个参数。 2. 查询状态的线程,以确保设备仍然连接着。如果用户关闭设备或设备本身以有趣的方式进行交互,则需要在 UI 中反映出状态更改。 3. 读取设备响应的串行端口的线程。
我的问题实际上与调试这种情况有关。似乎每个线程中的每一行都必须有断点才能进行调试;如果我在一个线程中断点,调试器就不会逐步执行该线程。我知道其他线程将继续更新,但是我正在调试的线程不应该像正常情况下一样从一行到下一行执行吗?然后,我可以使用“线程”选项卡在线程之间切换。
我提到我在使用 WPF,因为我不知道这是否会改变情况;也许会,也许不会。状态检查线程是 UI 控件的一部分,因为只需要在 UI 启动时检查状态。该控件位于与主应用程序不同的库中。

移除了 WPF 的引用,因为它与 WPF 不是真正相关的 - 只是通用的 MT 调试。 - Paul Alexander
不幸的是,我注意到vs2008开始表现得非常奇怪(这只是一个问题行为,其他问题涉及源代码控制和不同的构建设置),这是自从项目迁移到WPF以来发生的。因此,为了以防万一,我将其包含在内。 - mmr
3个回答

7
当调试器在断点处停止时,默认情况下会暂停所有其他线程。但是当您单步执行或继续执行时,所有3个线程都将恢复。当您通过代码进行单步调试时,调试器基本上在下一行上设置了一个临时断点并恢复了所有线程。在达到虚拟断点之前,其他2个线程可能有机会运行。 您可以在调试时冻结其他线程 当您在断点处时,请选择调试|窗口|线程。选择您不感兴趣的线程,右键单击,选择冻结。这将让您专注于正在单步执行的一个线程。

但我的观点是它没有触发那个临时断点;它只是毫不费力地继续执行,除了原始的断点之外没有触发任何其他断点。我希望其他线程能够运行;我想要能够看到它们的错误行为。 - mmr
当您手动步进并中断后会发生什么? 它是否在 Win32 方法的某个地方丢失,还是实际上在稍后的代码中某个点停止? - Paul Alexander
它永不停息,只会继续前行。 - mmr
听起来你的VS安装出了问题。尝试在另一台机器上运行,看看是否有相同的行为。 - Paul Alexander

1

如果您的代码以奇怪的方式单步执行,有时可能是由于简单的损坏的pdb文件引起的。对代码进行“全部重新构建”将从头开始重新生成它,并解决任何此类故障。

另一件需要记住的事情是,在调试器中停止一个线程可能会导致各种不寻常的时间问题,这些问题在发布版本中是看不到的。例如:

  • 串行端口将始终在断点上停止时(在硬件/驱动程序级别上)继续操作-当您下次尝试单步执行代码时,它可以接收突然的大量数据。对于异步回调,这可能会很“有趣”。

  • 停止一个线程会干扰正常的时间分片,因此线程之间的同步可能会出现问题。


1

我同意Jason的观点,单纯的步进已经不能再展示真相了。

最好的方法是在每行代码中插入一个方法,并使用Interlocked.Increment增加计数器并将计数器添加到输出中(最好使用本地文件)。

由于实际事件的顺序并不总是与写入文件的顺序相同,所以需要计数器。在输出中命名线程或使用ID值也是必要的。我使用MS Excel打开文件并根据线程对所有行进行着色,这样我可以非常清楚地看到交错操作。

我甚至编写了一个包装器来锁定{},它会在每次锁定时进行插装。

同步问题很难排查,因此我建议不要花费比重构更多的时间。有时这表明您采取的方法是次优的。

记得在IO中必要时使用volatile。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接