在 C # 中检测到 ContextSwitch 死锁错误

我正在运行一个 C # 应用程序,在运行时我得到了以下错误:

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

有人能帮我解决这个问题吗?

非常感谢。

84309 次浏览

此消息表明您的某些代码正试图切换线程,而目标线程正忙。例如,一个后台线程试图调用 UI 线程来更新 UI,而 UI 运行了一段时间的紧凑循环。

要真正弄清楚发生了什么,您需要进入调试器,查看所有线程以及它们正在做什么。

程序的主线程已经忙于执行代码一分钟了。它没有照顾好自己的正常职责,不停地循环传递信息。当您在辅助线程中使用 COM 服务器时,这是非法的: 对它们的方法的调用不能被发送,直到您的主线程再次空闲。

它应该很容易看到,你的用户界面应该像门钉一样死了。Windows 应该用一个显示“未响应”的幽灵替换你的主窗口。关闭窗口不会工作,没有单击事件有任何影响。

无论你的主线程在做什么,都应该由一个工作线程来完成。BackgroundWorker类对此很有帮助,您将在 MSDNLibrary 文章中找到许多关于它的使用帮助。如果不知道主线程在做什么,请使用“调试 + 中断所有”、“调试 + Windows + 线程”。

另一个可能的原因是: 如果您使用的是 VS2005的 RTM 版本,请确保安装 ServicePack1。

只需在视觉工作室2005窗口中的 Debug 菜单中选择 Exception,Edxception 对话框就会弹出,选择 Managed Debug Assistant Exception Node,然后选择 ContextSwitch Deadlock 并从 Throw 列中删除选择。这将阻止 vs 抛出 ContextSwitch 死锁异常。

希望这个能帮上忙。

在某些情况下:
调试-> 异常-> 托管调试助手
并取消选中 ContextSwitch Deadlock 项。

要查明哪个操作阻塞了上下文切换并导致显示 死锁 MDA,可以使用以下步骤。注意,我将引用 VisualStudio2012。

  1. 重现错误。这可能涉及一些试错。
  2. 在显示的托管调试助手中单击“确定”而不是“继续”。
  3. 右键单击工具栏对接区域并选择“调试位置”,以确保“调试位置”工具栏处于活动状态。如果工具栏处于活动状态,您应该会看到一个标签为“ Thread”的下拉列表。
  4. “线程”下拉列表中的选定项应该是主线程以外的一个线程,因为它将是一个后台线程,抱怨主线程霸占了所有的注意力。在下拉列表中选择主线程。
  5. 您现在应该在代码编辑器中看到阻塞上下文切换的代码。

假设您决定不将资源密集型操作从主线程上移开——在此之前请看一下其他一些答案和注释——您可以使用以下选项禁用托管调试助理。

在 VisualStudio 调试器中

  1. 您可以在 MDA 对话框中直接禁用 MDA,该对话框是 当错误发生时,通过取消选中“当此 引发异常类型’。
  2. 异常设置对话框使用以下 MSDN中的说明。

... 在“调试”菜单上,单击“异常”。(如果“调试”菜单不包含“异常”命令,请单击“工具”菜单上的“自定义”以添加该命令。)在“异常”对话框中,展开“托管调试助手”列表,然后清除各个 MDA 的“抛出”复选框。

在 VisualStudio 调试器外部

  1. 注册表项 (机器范围,所有 MDA 受影响)
  2. 环境变量 (可指定计算机范围内的 MDA)
  3. 应用程序配置设置 (应用程序范围,可以指定 MDA)

注意: 前两个选项中的一个必须设置为1才能使第三个选项生效。

在我的例子中,问题是在一个控制台应用内对实体框架中的 SaveChanges ()的调用。用 MTAThreadAttribute应用于 Main()方法 不再引发 ContextSwitch 死锁异常。不幸的是,我不能确定这种变化的全部影响。

当我试图弄明白为什么我的 OracleDataReader会抛出一个异常时,我遇到了这个问题。我认为这是因为它被赋予了 null,因为这个异常与一个‘ null’参数有关。所以我照做了:

while (dr.Read())
{
while (dr != null)  // <-- added this line
{
...

原来 dr从来都不是空的,所以循环一直持续下去,直到这条消息到来,然后继续下去,因为你可以点击“继续”,直到内存耗尽(不要这样做,而是点击“确定”)。这个故事的寓意是,寻找内存泄漏,这些内存泄漏将数据从数据库以循环的方式传输到内存中,直到永远。这个错误实际上是试图警告您一个糟糕的场景。最好留意一下。

这个错误出现了很多次,我跟踪它到 DataGridViewRow中的一次迭代,在这次迭代中,我将复选框的值设置为 true。因为我是在调试模式下运行的,所以我可以选择继续,所以我可以这样做。

我希望这能帮到别人。

假设您正在使用 VisualStudio,可以在当前项目中单击 Ctrl+Alt+E,异常窗口将显示为 select 托管调试助手您应该取消选中“ ContextSwitch 死锁”选项。然后生成当前项目。

最后,我为我的 vb.net Windows 应用程序表单找到了一个可行的解决方案

Application.DoEvents ()

语句在循环中的某个位置。

参考资料: https://earlybites.wordpress.com/2012/04/10/resolution-context-switch-deadlock-was-detected/