.NET 4.0和可怕的OnUserPreferenceChanged Hang

我一直受到可怕的OnUserPreferenceChanged Hang的困扰,Ivan Krivyakov在这里很好地提到了这里:

http://ikriv.com/en/prog/info/dotnet/MysteriousHang.html#BeginInvokeDance

我刚回来时发布了一个问题,当时我最初遇到问题:

又一个C#死锁调试问题

我以为我已经通过移除一个由UI线程构建的Control来解决它,但过了一会儿它再次出现(可能永远不会离开……)。

我们一直在使用.NET 3.5,据我所知使用的是CLR 2.0。 最近,applciation已升级为使用.NET 4.0 Client Profile / CLR 4.0。 此外,我们已从Infragistics WinForms 10.1升级到10.3。 唯一的另一个区别是以前的版本是混淆的……有没有人遇到过混淆和挂起的问题?

我已经再次尝试摆脱任何应用程序挂起一次又一次,但不同寻常的是,我无法在最新版本中重现挂起(使用.NET 4.0)。 使用Ivan Krivyakov的方便的Freezer应用程序(请参阅他的文章),可以根据请求触发WM_SETTINGCHANGE消息,以便在以前的版本(使用.NET 3.5)中重现。

可能是我有点希望问题已经从它自己的消失中消失了,但是有人知道CLR从2.0到4.0是否有任何变化会导致这种情况发生?

————————————————– – -解 – – – – – – – – – – – – – – – – – – – – – – – —-

因此,在测试应用程序的变体后,例如CLR 2.0 + Infragistics 2010.1,CLR 2.0 + Infragistics 2010.3和CLR 4.0 + Infragistics 2010.1,我们相信我们已经确定问题是WinForms 2010.1中的Infragistics组件的问题(没有热修复) )。 我们仍然没有使用CLR 2.0或CLR 4.0与Infragistics 2010.3重现冻结(现在我们已经非常擅长再现这个……)。

一个由UI线程构建的控件……

是的,这是触发此问题的好方法。 底层问题是由SystemEvents类引起的,它具有在正确的线程上引发事件的不可靠任务。 UserPreferenceChanged事件是典型的麻烦制造者,许多控件订阅它,以便他们可以在用户更改桌面主题时重新绘制自己。 组件供应商不会忽视对此的需求。 工具箱中的标准.NET框架控件也不是。

测试此问题的一种通常不错的方法是锁定工作站(按下Win + L键),以及通常在用户计算机上触发死锁的方式。 切换到安全桌面往往会触发事件。 有了额外的怪癖,当你调试你的程序时它永远不会发生,并且它有棘手的时间相关的行为,因为这往往发生在没有人在机器上。 额外难以调试。

像这样陷入麻烦的一种标准方法是由于程序中的初始化问题。 订阅的第一个SystemEvents事件会导致SystemEvents类初始化自身并设置接收这些通知和引发其相应事件所需的管道。 一个自定义的启动屏幕(它不仅仅显示一个位图)并在标记为STA的工作线程上运行就足以让这个错误。 像ProgressBar这样简单的东西已经足够了。 SystemEvents假定工作线程是程序的主线程,现在可以在将来轻松地在错误的线程上生成事件。 对此有一个很好的诊断,如果那个工作线程不再存在,那么会产生第一次机会exception。 您可以在“输出”窗口中看到它。

或者您创建另一个UI线程并在两个线程上都有表单。 不可避免地,这些forms中的一个总是会在错误的线程上获得事件。

唯一不错的建议是承认在工作线程上创建UI是微软不知道如何正确执行的火箭科学。 值得注意的是.NET 1.x控件有一个事件处理程序,当从错误的线程调用它时它仍能正常工作,它只调用Control.Invalidate()。 但是,知识似乎在2.0时已经丢失,ToolStrip就是一个很好的例子 。 并且不要相信组件供应商能够做到这一点,特别是Infragistics没有一流的声誉。 不要这样做。

我找到解决此问题的最佳指南是:

  • SystemEvents.UserPreferenceChanged期间调试Windows窗体应用程序挂起 – DSUI团队博客 – 站点主页 – MSDN博客

它将引导您使用WinDbg来validation错误原因,并向您展示如何找到导致错误的原因。 正如您所提到的,很可能是因为在非ui线程上创建了一个控件。

在我的情况下,我通过创建一个工厂来解决问题,该工厂使用UI线程中的SynchronizationContext来创建控件,然后我调用CreateControl()以强制创建UI句柄。

Microsoft支持文章位于:

  • 更改系统设置或锁定工作站时,Windows窗体应用程序将冻结

如果您使用第一个CLR 2.0然后再使用CLR 4.0从他的网页运行示例应用程序,那么您会注意到问题似乎真的在4.0中消失了 – 不知道已经改变了什么,但也许他们真的解决了这个问题。 BR