且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

接口在多线程C#应用程序中冻结

更新时间:2022-04-08 22:51:40

当您使用非标准方式初始化用户界面时,这是SystemEvents类通常引起的问题.特别是使用线程.启动程序,调试+全部破坏,调试+ Windows +线程.如果您看到一个名为".NET SystemEvents"的线程,那么您肯定可以将其挂起.

This is a problem that's commonly induced by the SystemEvents class when you have a non-standard way to initialize your user interface. Using threads, specifically. Start your program, Debug + Break All, Debug + Windows + Threads. If you see a thread named ".NET SystemEvents" then you're pretty much guaranteed to get this hang.

某些背景:SystemEvent类同时支持控制台模式应用程序和GUI应用程序.对于后者,它应该在UI线程上触发其事件处理程序.第一次预订其事件之一时,它会创建一个不可见的帮助程序窗口以获取系统通知.它可以通过在调用线程上创建窗口或启动帮助程序线程来完成这两种方式.它基于Thread.GetApartmentState()的值进行决策.如果它是STA,则可以在调用线程上创建窗口,并且所有事件回调都可以正确地编组到该线程.

Some background: the SystemEvent class supports both console mode apps and GUI apps. For the latter, it should fire its event handlers on the UI thread. The very first time one of its events is subscribed, it creates a little invisible helper window to get the system notifications. It can do this two ways, either by creating the window on the calling thread or by starting up a helper thread. It makes the decision based on the value of Thread.GetApartmentState(). If it is STA then it can create the window on the calling thread and all event callbacks can be properly marshaled to that thread.

如果未在UI线程上创建您创建的 first 窗口,则会出错.例如启动画面.该窗口可能包含对系统事件感兴趣的控件,例如UserPreferenceChanged,以便它们可以正确地重新绘制自己.现在,它使用帮助程序线程,并且将从该帮助程序线程而不是UI线程中触发任何事件.毒害在UI线程上运行的任何窗口.出于某种神秘的原因,从锁定的工作站(包括屏幕保护程序)中退出会话很可能导致死锁.您可能还会看到偶尔的绘画事故,这是使用来自错误线程的窗口带来的较不愉快的结果.

This goes wrong if the first window you create is not created on the UI thread. A splash screen for example. That window may contain controls that are interested in a system event like UserPreferenceChanged so they can properly repaint themselves. It now uses the helper thread and any event will be fired from that helper thread, not the UI thread. Poison to any window that runs on the UI thread. The session switch out of a locked workstation (including the screen saver) is for some mysterious reason very likely to cause deadlock. You may also see an occasional painting mishap, the less nasty result of using windows from the wrong thread.

不固定初始化顺序,一种解决方法是在创建任何窗口之前,将其放入Main()方法中.

Short from fixing the initialization order, a workaround is to put this in your Main() method, before any windows are created:

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