我有一个c#.NET多线程应用程序,它冻结了界面。这有什么不寻常之处在于界面不会冻结,除非我让系统闲置足够长时间以启动屏幕保护程序(这需要我重新输入我的密码以重新获得对系统的访问权限)。当界面再次可见时(在我成功输入密码后),所有窗口都是白色的。我可以看到窗口标题,移动窗口,最小化它们等,但屏幕没有重新绘制。当我中断所有并进入调试器时,调用堆栈具有Application.Run(),外部代码,然后“处于休眠状态,等待或加入”。我在我打开的所有四个线程中都设置了断点并且它们仍在运行,它只是主要应用程序的UI线程被阻止。当我查看我的线程列表时,我的主线程和我的四个工作线程现在由我的主线程和11个工作线程组成。我没有打开这么多线程所以它必须是serialport类。
现在让我来描述我的节目。
我的主应用程序允许用户从串口收集和监控数据。我已通过以下方式实现了这一点。当需要连接时,在主应用程序上按下一个按钮,该按钮调用DLL中的函数,该函数打开状态窗口,然后启动监视串行端口的线程。当该函数返回时,主应用程序启动一个线程来监视在初始化时在DLL中创建的队列。从串行端口接收数据时,将解析数据,然后更新状态窗口(通过委托),并将数据推送到队列中。当主应用程序工作者线程看到队列中的数据时,它会检索它并使用委托将其发布到主应用程序的列表框中。在所有情况下,我都使用BeginInvoke来调用这些代理。
我的DLL包含两个库,可用于与之通信的两种不同类型的设备。
当我连接到两个设备时会发生此问题;因此每个设备有四个工作线程两个。 DLL本身被设置为comm对象,因此我可以从C ++ / MFC应用程序和c#app轻松访问它,两者都使用它。
我发现如果我在DLL内部的线程中添加代码,每30秒调用一次Application.DoEvents(),接口将被冻结约30秒,然后恢复活动,就像正常一样。我认为阻塞主线程的东西并强制DoEvents()触发似乎打破了锁定,但我不知道是什么原因导致这个锁定。这不是解决方案,只是感兴趣的东西。
我很感激您的任何建议。感谢。
答案 0 :(得分:2)
我发现如果我在DLL内部的线程中添加代码,每30秒调用一次Application.DoEvents(),接口将被冻结约30秒,然后恢复活动,就像正常一样。我认为阻塞主线程的东西并强制DoEvents()触发似乎打破了锁定,但我不知道是什么原因导致这个锁定。这不是解决方案,只是感兴趣的东西。
我建议在新的Visual Studio 2010 Concurrency Profiler下运行您的程序。这将在运行时向您显示哪些线程被阻止,以及它们正在等待哪些对象。线程争用已明确标记并为您突出显示。
您可以使用它来轻松确定导致UI线程死锁的代码。
答案 1 :(得分:1)
尝试将您的主题开始代码更改为Thread.Start()
而不是BeginInvoke()
。 BeginInvoke不会保持线程与您的UI分离,因为它可能与DoEvents奇怪地交互。您可以在这里阅读BeginInvoke及其工作原理:http://www.codeproject.com/KB/cs/begininvoke.aspx
此外,DoEvents在应用程序中永远不是必需的,并且可能导致许多意外行为。对包含在Control.Invoke(...)语句中的UI调用使用threadding。如果您使用的是.NET 3.5+,则可以使用如下代码轻松实现此目的:Invoke((Action)delegate() {*code goes here*});