【问题标题】:Why does the Visual Studio debugger not show the state machine code generated by the await keyword?为什么 Visual Studio 调试器不显示 await 关键字生成的状态机代码?
【发布时间】:2016-10-06 13:11:18
【问题描述】:

当我在等待的方法主体中设置断点时,Visual Studio 调试器会显示一个调用堆栈,其中没有任何 C# 编译器生成的代码。

请看下图,它显示了我简单的async 方法和调用堆栈。

请注意,在调用堆栈中没有调用MoveNext 或初始化状态机对象或TaskAwaiter<TResult>AsyncTaskOfTMethodBuilder

为什么会这样?就像 IL Spy 中的一样,Visual Studio 中是否有一些设置可以切换,以便在调试会话正在进行时让它在调用堆栈和编辑器中显示状态机代码?

我突然想起在重写的按钮单击处理程序代码中有一个DebuggerStepThroughAttribute,用于实例化状态机。但我不确定这是否是它对调试器隐藏的原因。这不应该只是将调用堆栈中编译器生成的方法的堆栈框架变灰吗?

DebuggerHiddenAttribute 不是让代码对调试器不可见吗?

【问题讨论】:

  • 你的断点在另一个线程上运行的任务中,为什么会有创建那个线程的调用堆栈的证据?您是否检查了可以在调试器中获得的单独线程窗口?我不记得名字了,但是你可以打开一个窗口/窗格来显示程序中所有线程的状态。
  • 但是,问题是按钮单击事件处理程序方法暂时完成了。它已经返回,这可能发生在额外线程启动期间的前几毫秒,这意味着不仅运行任务的线程的调用堆栈不会显示按钮事件处理程序,而且您正在寻找的方法很可能已经返回。

标签: .net visual-studio async-await visual-studio-2015


【解决方案1】:

这里有几点需要注意。

首先,你有 2 个线程在玩:

  1. 主线程,运行消息泵并拥有其中包含按钮的窗口
  2. 正在运行任务的线程

一个线程内的调用堆栈绝不会反映创建它的线程当前正在做什么。

如果您检查可以显示调试器中所有线程及其调用堆栈的调试器窗格,您最多会看到这两个线程及其调用堆栈。

但是,如果在调试器遇到断点时执行此方法的线程仍在该方法中,这只会显示按钮事件处理程序。由于启动新线程的开销,这很可能不是真的。

原因是async/await 在遇到await 时从async 方法返回。当单独的线程开始执行您的委托时,按钮事件处理程序方法很可能已经返回。

即使您为您的委托手动启动一个线程并加入(等待)该线程,您也不会在 callstack 中看到它,但您绝对应该在其他调试器中看到它线程及其调用堆栈的窗格。

【讨论】:

  • 哦,是的。我的错。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-04-17
  • 1970-01-01
  • 2021-04-22
  • 1970-01-01
  • 1970-01-01
  • 2015-10-09
  • 1970-01-01
相关资源
最近更新 更多