C# · 12月 23, 2021

c# – .NET 4.0和可怕的OnUserPreferenceChanged挂起

我一直困扰着可怕的OnUserPreferenceChanged Hang,这是非常好的Ivan Krivyakov,在这里:

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

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

Yet another C# Deadlock Debugging Question

我以为我已经通过删除一个从UI线程构建的控件来解决它,但是在一段时间后它再次出现(可能从未离开…).

我们一直在使用.NET 3.5,我理解使用CLR 2.0.最近,应用程序已升级为使用.NET 4.0 Client Profile / CLR 4.0.此外,我们已经从Infragistics WinForms 10.1升级到10.3.唯一的区别是,以前的版本是模糊的…有任何人遇到混淆和悬挂的问题吗?

我已经有了另一个刺,一劳永逸地摆脱任何应用程序挂起,但异常地,我无法在最新版本(使用.NET 4.0)中重现挂起.在以前的版本(使用.NET 3.5)中,使用Ivan Krivyakov的方便的Freezer应用程序(参见他的文章),这个挂起很简单,可以根据要求触发WM_SETTINGCHANGE消息.

这可能是我有点希望,这个问题自己已经消失了,但是有谁知道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重现冻结,而是(现在我们已经非常擅长再现这个…).

解决方法 它是由程序中的初始化问题引起的.订阅的第一个SystemEvents事件导致SystemEvents类自己初始化并设置接收这些事件所必需的管道.它创建一个隐藏的窗口,以便它可以接收通知消息,如WM_SETTINGCHANGE.您在表单中使用的控件经常订阅UserPreferenceChanged事件,以便用户在更改Windows主题或系统颜色时自行重画.

当第一个控件是没有在主线程上创建的控件时,这会出错. SystemEvents通知这个并创建一个帮助线程来服务隐藏的窗口.当例如控制台模式程序想要使用这样的系统事件时重要.从那里开始,订阅的事件处理程序从辅助线程而不是主线程生成.如果那个事件处理程序然后用UI做某事,死锁的可能性很高,windows不是线程安全的.您可以从“调试Windows线程”窗口中诊断,您将看到名为“.NET SystemEvents”的帮助线程.

这个问题的典型来源是一个自定义的启动屏幕,在主线程自身初始化时,在工作线程上创建.避免这种情况,并使用内置的.NET支持来启动屏幕.另一个原因是程序中没有[STAThread]属性的Main()入口点.在调用Application.Run()之前,在程序初始化时启动一个工作线程的任何其他类型的代码是一个潜在的麻烦制造者.

如果您没有任何线索代码可能正在做什么,那么您可以通过在Main()方法中订阅一个虚拟系统事件来解决这个问题,从而确保在主UI线程上始终创建隐藏的通知窗口.在EnableVisualStyles调用之后,将此代码粘贴到Main方法中:

Microsoft.Win32.SystemEvents.UserPreferenceChanged += delegate { };