在C#中检测到ContextSwitchDeadlock错误


79

我正在运行C#应用程序,并且在运行时出现以下错误:

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

任何人都可以在这里帮助我解决这个问题吗?

非常感谢。

Answers:


123

程序的主线程忙于执行代码一分钟。它没有执行正常的任务,因此会增加消息循环。在工作线程中使用COM服务器时,这是非法的:在主线程再次变为空闲之前,不能调度对它们方法的调用。

它应该清晰可见,您的UI应该像门钉一样死掉。Windows应该已经用显示“无响应”的重影替换了主窗口。关闭窗口将不起作用,任何单击事件均无效。

无论您的主线程在做什么,都应该由工作线程代替。该BackgroundWorker班是好为,你会发现在MSDN Library文章为它在许多使用帮助。如果您不知道主线程在做什么,请使用“调试+全部破坏”,“调试+ Windows +线程”。

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


5
+1用于解释应将此类工作项移至辅助线程,从而提供有关如何避免此错误(而不是仅产生错误的解决方案)的解决方案。
JYelton 2011年

2
有趣的是,我看到其他一些内部构建的应用程序的挂起时间比我的挂起的时间长得多,但是我遇到了这个错误消息,hmmm。
合作社2012年


1
感谢您的详细说明,我使用的变通办法是异步功能,这现在非常合理。因此,据我了解,为长时间运行的操作(尤其是在使用COM时)管理新线程非常重要。
Anthony Mason

50

若要查找哪个操作正在阻止上下文切换并导致显示contextSwitchDeadlock MDA,可以使用以下步骤。请注意,我将指的是Visual Studio 2012。

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

假设您决定不将资源密集型操作移出主线程-在执行操作之前先查看此处的其他一些答案和评论-您可以使用以下选项来禁用托管调试助手。

在Visual Studio调试器中

  1. 您可以通过取消选中“抛出此异常类型时中断”,直接在发生错误时显示的MDA对话框中禁用MDA。
  2. 使用“异常设置”对话框,使用MSDN中的以下说明。

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

在Visual Studio调试器之外

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

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

就我而言,问题是在控制台应用程序中的实体框架中调用ObjectContext.SaveChanges()。将MTAThreadAttribute应用于该Main()方法后,不再引发ContextSwitchDeadlock异常。不幸的是,我不确定这种改变的全部影响。


2
支持对找到阻止该过程的代码的明确解释进行投票。
Guillaume Schuermans 2013年

10

此消息表明您的某些代码正在尝试切换线程,并且目标线程正忙。例如,后台线程试图将调用调度到UI线程以更新UI,而UI则运行紧密循环一段时间。

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


4

在某些情况下:
调试->异常->托管调试助手,
然后取消选中ContextSwitchDeadlock项。


5
是的,但是当您编写一次测试时,这很碍您,可以禁用它。
Tod

4
没有错。这不是解决问题的方法。
汤姆W

3
您必须像工程师而不是科学家那样思考!!
Ehsan Zargar Ershadi

4
@Ehsan Ershadi,一名优秀的工程师可以预见并解决问题,而不是将其推到地毯下!
Mo Patel

3
大声笑。如果您不想看到该错误,则可以只看显示器以外的其他地方。这与您的“解决方案”相同。这不是解决方案。这只是无礼!
curiousBoy 2014年

0

只需从Visual Studio 2005窗口的“调试”菜单中选择“异常”,然后弹出“ Edxception”对话框,选择“托管调试助手异常节点”,然后选择“ ContextSwitchDeadlock”并从“抛出”列中删除选择。这将阻止vs引发ContextSwitchDeadlock异常。

希望这可以帮助..


60
你的手臂着火了。只需用刀切开神经即可使您的大脑痛苦。这样可以避免您注意到手臂着火了。
奥扎(Ozzah)

无论如何,这是暂时解决问题的一种方法。为了彻底解决此问题,需要一些时间重新考虑应用程序的设计。
王继军

0

当我试图弄清楚为什么我OracleDataReader抛出异常时,我遇到了这个问题。我以为是因为null异常与“ null”参数有关而被分配。所以我做了:

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

原来那dr是永远不会为null的,所以循环一直进行下去,直到此消息到达为止,然后继续进行下去,因为您可以单击“继续”以使其继续进行,直到内存用完为止(不要这样做-点击“确定”)。故事的寓意如此,寻找内存泄漏,这些泄漏是将数据从数据库流到无限循环的内存中。该错误实际上是在警告您出现不良情况。最好注意这一点。


0

这个错误对我来说无数次出现,我将其追溯到中的一个迭代DataGridViewRow,其中将复选框的值设置为true。由于我在调试模式下运行,因此我可以选择继续,因此我能够做到这一点。

我希望这可以帮助别人。


0

假设您使用的是Visual Studio,则可以Ctrl+Alt+E在当前项目中单击,并且将显示带有选择的托管调试助手的例外窗口,您应该取消选中“ ContextSwitchDeadlock”选项。然后构建一个当前项目。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.