我有一个c#.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内的状态窗口,但这没有任何区别。
我多年来一直在做多线程编程,从未见过这样的事情。所以任何建议都会非常感激。
感谢。
答案 0 :(得分: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 { };
答案 1 :(得分:0)
问题确实与ActiveX控件有关,可能在表单中使用不正确。我转而使用.NET中的串口库,但无法重现我的问题。感谢大家,特别是汉斯的帮助。
答案 2 :(得分:0)
我遇到了同样的问题,因为当屏幕保护程序启动或我锁定我的电脑和显示器进入睡眠状态时,我的电脑就会挂起。 我95%确定我的多线程应用程序中出现死锁。查看并确定代码中是否存在任何死锁。