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

Phi*_*yro 1 c# multithreading

我有一个冻结界面的ac#.NET多线程应用程序.这有什么不寻常之处在于界面不会冻结,除非我让系统闲置足够长时间以启动屏幕保护程序(这需要我重新输入我的密码以重新获得对系统的访问权限).当界面再次可见时(在我成功输入密码后),界面被锁定.只要我不让屏幕保护程序启动,那么界面就不会锁定.

我应该指出,我有两个不同的可执行文件访问相同的DLL,无论我使用哪个应用程序访问DLL,都会出现此问题.这似乎意味着问题出在DLL中,因为两个应用程序完全不同(C++/MFC)和(C#/ .NET),除了它们与DLL的关系.

两个exes在如何与DLL交互时执行类似的步骤.他们调用dll来设置串口通信,打开DLL中的状态窗口,启动DLL中的线程来监视comm端口,然后在主应用程序中启动一个监视dll中堆栈的线程.

当DLL中的线程从通信端口获取数据时,将对其进行解析,并将其结果放在堆栈上,然后通过委托将其发布到状态窗口.当exe中的线程看到堆栈中的数据时,它也会使用委托在主窗口中输出数据.

我发现如果我在DLL中的线程中添加代码,每30秒调用一次Application.DoEvents(),接口将被冻结约30秒,然后恢复活动,就像正常一样.我认为阻塞主线程的东西并强制DoEvents()触发似乎打破了锁定,但我不知道是什么原因导致这个锁定.

在我的开发计算机和测试计算机上都会出现此问题.

我已经尝试将数据输出完全删除到DLL内的状态窗口,但这没有任何区别.

多年来我一直在做多线程编程,从未见过这样的事情.所以任何建议将不胜感激.

谢谢.

Han*_*ant 6

当您使用非标准方法初始化用户界面时,这是一个通常由SystemEvents类引起的问题.特别是使用线程.启动程序,Debug + Break All,Debug + Windows + Threads.如果你看到一个名为".NET SystemEvents"的线程,那么你几乎可以保证得到这个挂起.

一些背景知识:SystemEvent类支持控制台模式应用程序和GUI应用程序.对于后者,它应该在UI线程上触发其事件处理程序.第一次订阅其中一个事件时,它会创建一个不可见的辅助窗口来获取系统通知.它可以通过在调用线程上创建窗口或启动辅助线程两种方式来完成.它根据Thread.GetApartmentState()的值做出决定.如果它是STA,那么它可以在调用线程上创建窗口,并且所有事件回调都可以正确地封送到该线程.

如果您创建的第一个窗口未在UI线程上创建,则会出错.例如一个闪屏.该窗口可能包含对UserPreferenceChanged等系统事件感兴趣的控件,以便他们可以正确地重新绘制自己.它现在使用辅助线程,任何事件都将从该辅助线程而不是UI线程触发.对UI线程上运行的任何窗口的毒害.会话切换出锁定的工作站(包括屏幕保护程序)是出于某种神秘的原因,很可能导致死锁.您可能还会看到偶尔的绘画事故,从错误的线程使用Windows的不那么令人讨厌的结果.

除了修复初始化顺序之外,解决方法是在创建任何窗口之前将它放在Main()方法中:

Microsoft.Win32.SystemEvents.UserPreferenceChanged += delegate { };
Run Code Online (Sandbox Code Playgroud)