Visual Studio:上下文切换死锁

Posted

技术标签:

【中文标题】Visual Studio:上下文切换死锁【英文标题】:Visual Studio: ContextSwitchDeadlock 【发布时间】:2010-10-09 08:47:09 【问题描述】:

我收到一条我无法解决的错误消息。它源自 Visual Studio 或调试器。我不确定最终的错误情况是在 VS、调试器、我的程序还是数据库中。

这是一个 Windows 应用程序。不是网络应用。

来自 VS 的第一条消息是一个弹出框,上面写着: “没有为任何调用堆栈帧加载任何符号。无法显示源代码。” 当它被点击时,我得到: “检测到 ContextSwitchDeadlock”,以及下面复制的一条长消息。

错误出现在向下扫描 DataTable 的循环中。对于每一行,它使用表中的键 (HIC #) 值作为 SqlCommand 的参数。该命令用于创建返回一行的 SqlDataReader。比较数据。如果检测到错误,则会将一行添加到第二个 DataTable。

错误似乎与程序运行所需的时间(即 60 秒后)有关,而不是发现了多少错误。我不认为这是一个内存问题。循环内没有声明任何变量。创建的唯一对象是 SqlDataReaders,它们位于 Using 结构中。添加 System.GC.Collect() 没有效果。

数据库是同一台笔记本电脑上的 SqlServer 站点。

表单上没有花哨的小玩意或小工具。

我不知道这个过程中有什么与我之前做过的几十次有很大不同的地方。我以前见过这个错误,但从来没有一致的基础。

有什么想法吗?

完整的错误文本: CLR 在 60 秒内无法从 COM 上下文 0x1a0b88 转换到 COM 上下文 0x1a0cf8。拥有目标上下文/单元的线程很可能要么进行非泵送等待,要么处理非常长时间运行的操作而不泵送 Windows 消息。这种情况通常会对性能产生负面影响,甚至可能导致应用程序变得无响应或内存使用量随着时间的推移不断累积。为避免此问题,所有单线程单元 (STA) 线程都应使用泵送等待原语(例如 CoWaitForMultipleHandles)并在长时间运行的操作期间定期泵送消息。

【问题讨论】:

【参考方案1】:

ContextSwitchDeadlock 并不一定意味着您的代码有问题,只是有可能。如果你在菜单中去Debug > Exceptions并展开Managed Debugging Assistants,你会发现ContextSwitchDeadlock被启用了。

如果您禁用此功能,当项目需要很长时间处理时,VS 将不再警告您。在某些情况下,您可能有效地进行了长时间运行的操作。如果您正在调试并且在处理过程中停止在线,这也很有帮助 - 在您有机会深入研究问题之前,您不希望它抱怨。

【讨论】:

正确!谢谢。我确实必须去自定义并将异常添加到调试菜单。不是 UI 最直观的方面。工具\自定义,然后重新排列命令(按钮),然后从右上角的下拉列表中选择调试,然后添加(按钮)。哇! ctrl-alt-e 带来异常对话框。 许多较新的 Visual Studio 版本(2012、2010、2008)以及可能的一些早期版本,允许在安装后首次运行 Visual Studio 时选择它的主要用途。该选择决定了工具栏的默认布局,包括哪些控件可见或隐藏,甚至哪些击键对应于哪些命令。在 VS 2010 中,导入和导出设置向导允许您重置为可用的默认值之一。 @B.ClayShannon - ContextSwitchDeadlock 特定于调试器。 exe 的发布版本不会显示此消息。 在 VS 2013 中使用 Debug -> Windows -> Exceptions Settings 导航。然后使用搜索【参考方案2】:

在 Visual Studio 2017 中,通过以下方式取消选中 ContextSwitchDeadlock 选项:

调试 > Windows > 异常设置

在异常设置窗口中:取消选中 ContextSwitchDeadlock 选项

【讨论】:

在 VS 2019 Pro 中仍然有效【参考方案3】:

正如 Pedro 所说,如果您单步执行代码,调试器会阻止消息泵。

但是,如果您在 UI 线程上执行长时间运行的操作,则调用 Application.DoEvents() 显式抽取消息队列,然后将控制权返回给您当前的方法。

但是,如果您这样做,我建议您查看您的设计,以便您可以在 UI 线程之外执行处理,从而使您的 UI 保持美观和活泼。

【讨论】:

【参考方案4】:

听起来您正在应用程序的主 UI 线程上执行此操作。 UI 线程负责在到达时发送 Windows 消息,但由于您的消息在数据库调用中被阻塞,因此无法这样做。这可能会导致系统范围的消息出现问题。

您应该考虑为长时间运行的操作生成一个后台线程,并在它发生时为用户设置某种“我很忙”对话框。

【讨论】:

【参考方案5】:

如果您不想禁用此异常,您需要做的就是让您的应用程序至少每 60 秒发送一次消息。它将防止发生此异常。 尝试不时调用 System.Threading.Thread.CurrentThread.Join(10)。您还可以通过其他调用来让消息激增。

【讨论】:

您能解释一下为什么这会有所帮助吗? 这不起作用,我有一个循环更新 UI 并且仍然收到错误消息。 没有必要使用 10 毫秒的值,事实上如果你打算在长时间运行的操作中重复调用它,那会大大降低整体性能(总执行时间)。只需将零传递给它。 我遇到了类似的问题。发现您的解决方案有效。谢谢!【参考方案6】:

上述解决方案在某些情况下很好,但在另一种情况下,当您进行单元测试并且当您的解决方案未设置为调试时尝试从测试资源管理器中“调试选定的测试”时会发生这种情况。

在这种情况下,您需要将解决方案从“发布”或任何设置更改为“调试”。如果这是问题所在,那么更改“ContextSwitchDeadlock”不会真正帮助您。

我自己错过了这个,因为错误消息太讨厌了,我没有检查明显的东西是调试设置!

【讨论】:

【参考方案7】:

在 Visual Studio 2017 西班牙文版中。

“Depurar”->“Ventanas”->“Configuración de Excepciones”

并搜索“ContextSwitchDeadlock”。 然后,取消选中它。 或者快捷方式

Ctrl+D,E

最好的。

【讨论】:

【参考方案8】:

您可以通过取消选中 contextswitchdeadlock 来解决此问题

Debug->Exceptions ... -> 展开 MDA 节点 -> 取消选中 -> contextswitchdeadlock

【讨论】:

【参考方案9】:

也有这个问题,我的解决方法是在我的线程中添加“等待”:

Await Task.WhenAll(taskList.ToArray())
Await Task.Run(myAction)

【讨论】:

【参考方案10】:

我收到此错误并将查询切换为异步 (await (...).ToListAsync())。现在一切都好。

【讨论】:

以上是关于Visual Studio:上下文切换死锁的主要内容,如果未能解决你的问题,请参考以下文章

Java从入门到精通!并发编程挑战:死锁与上下文切换

针对不同域运行 Visual Studio 负载测试比较

死锁;上下文切换;常用缓存淘汰策略FIFOLFULRU

在 Visual Studio 代码中管理任务和上下文

Java多线程 -- 线程的生命周期和状态什么是上下文切换线程死锁避免死锁 sleep() 方法和 wait() 方法的区别和共同点为什么调用 start() 方法会执行 run() 方法

C# 关键字 Visual Studio 2012