2011-01-11 88 views
1

我有一个C#.NET多线程应用程序冻结了界面。不寻常的是,除非我让系统闲置足够长的时间以使屏幕保护程序启动(这要求我重新输入密码以重新访问系统),否则界面不会冻结。当界面再次可见时(在我成功输入密码后),界面被锁定。只要我不让屏幕保护程序启动,那么界面不会锁定。多线程c#应用程序中的界面冻结

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

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

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

我发现,如果我将代码添加到DLL中的线程,因此它每30秒调用一次Application.DoEvents(),界面将被冻结约30秒,然后像平常一样恢复活动。 我认为某些东西阻塞了主线程并强制DoEvents()发射似乎破坏了锁定,但我不知道可能会导致此锁定。

在我的开发机器和测试机器上都会出现此问题。

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

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

谢谢。

+3

暂停调试器中冻结的用户界面并查看调用堆栈。 – SLaks 2011-01-11 15:35:25

+0

您是否尝试过仅从非UI线程调用DLL方法并编组到UI线程? – RobS 2011-01-11 15:36:35

回答

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 { }; 
0

的问题确实出现了相关的ActiveX控件可能是在形式上使用不正确。我切换到在.NET中使用串行端口库,并没有能够重现我的问题。感谢大家,尤其是汉斯的帮助。

0

我遇到了同样的问题,因为当屏幕保护程序启动或我锁定我的电脑和显示器进入睡眠状态时,我的电脑会挂断。 我95%确定在我的多线程应用程序中出现死锁。查看并确定代码中是否存在任何死锁。