C#中检测到ContextSwitchDeadlock错误

时间:2010-05-09 13:01:39

标签: c# multithreading

我正在运行C#应用程序,在运行期间我收到以下错误:

  

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

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

非常感谢。

8 个答案:

答案 0 :(得分:121)

程序的主线程一直忙于执行代码一分钟。它没有照顾它的正常职责,抽取信息循环。在工作线程中使用COM服务器时,这是非法的:在主线程再次空闲之前,无法调度对其方法的调用。

应该很容易看到,你的UI应该像门钉一样死了。 Windows应该使用显示“无响应”的重影替换主窗口。关闭窗口不起作用,没有任何点击事件有效。

无论你的主线程做什么,都应该由工作线程完成。 BackgroundWorker类对此有好处,您可以在MSDN Library文章中找到许多使用帮助。如果您不知道主线程在做什么,请使用Debug + Break All,Debug + Windows + Threads。

还有一个可能的原因:如果您使用的是RT200版本的VS2005,请务必安装Service Pack 1.

答案 1 :(得分:47)

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

  1. 重现错误。这可能涉及一些试验和错误。
  2. 在显示的托管调试助手中单击“确定”而不是“继续”。
  3. 通过右键单击工具栏停靠区域并选择“调试位置”,确保“调试位置”工具栏处于活动状态。如果它处于活动状态,您应该会在工具栏中看到标记为“Thread”的下拉列表。
  4. “线程”下拉列表中的选定项应该是主线程以外的线程,因为它将是一个后台线程,它抱怨主线程正在占用所有注意力。在下拉列表中选择主线程。
  5. 您现在应该看到代码编辑器中阻止上下文切换的代码。
  6. 假设您决定不从主线程移动资源密集型操作 - 请在执行之前先查看其他一些答案和注释 - 您可以使用以下选项禁用托管调试助手。

    在Visual Studio调试器

    1. 您可以直接在MDA对话框中禁用MDA 通过取消选中'Break when this'时显示错误 异常类型被抛出'。
    2. 使用以下MSDN
    3. 中的说明使用“例外设置”对话框
        

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

      在Visual Studio调试器之外

      1. Registry Key(全机,所有受影响的MDA)
      2. Environment Variable(可以指定机器范围,MDA)
      3. Application Configuration Settings(可以指定应用程序范围,MDA)
      4. 注意:前两个选项中的一个必须设置为1才能使第三个选项生效。

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

答案 2 :(得分:9)

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

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

答案 3 :(得分:3)

在某些情况下:
调试 - >例外 - >托管调试助手
并取消选中ContextSwitchDeadlock项。

答案 4 :(得分:0)

只需从Visual Studio 2005窗口的Debug菜单中选择Exceptions,弹出Edxception对话框,选择Managed Debugging Assistants Exception Node,然后选择ContextSwitchDeadlock并从Thrown列中删除select。这将阻止vs抛出ContextSwitchDeadlock异常。

希望这会有所帮助..

答案 5 :(得分:0)

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

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

原来,dr一直都是空的,所以循环一直持续到这个消息到来为止,还有一些,因为你可以点击“继续”继续它,直到你用完为止记忆(不要这样做 - 请点击“确定”)。故事的道德,寻找内存泄漏,将数据从数据库流式传输到内存中,循环到无穷大。该错误实际上是在试图警告您一个糟糕的情况。最好留意它。

答案 6 :(得分:0)

这个错误多次出现在我身上,我将其追溯到DataGridViewRow中的迭代,其中我将checkbox值设置为true。由于我在调试模式下运行,我可以选择继续,所以我能够做到这一点。

我希望这有助于某人。

答案 7 :(得分:0)

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