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

C# 多线程c应用程序中的接口冻结,c#,multithreading,C#,Multithreading,我有一个c.NET多线程应用程序,它正在冻结接口。不寻常的是,界面不会冻结,除非我让系统闲置足够长的时间,让屏幕保护程序启动,这需要我重新输入密码以重新访问系统。当我成功输入密码后界面再次可见时,界面被锁定。只要我不让屏幕保护程序启动,界面就不会锁定 我应该指出,我有两个不同的可执行文件访问同一个dll,无论我使用哪个应用程序访问dll,这个问题都会发生。这似乎意味着问题出在DLL中,因为除了它们与DLL的关系外,这两个应用程序是完全不同的C++/MFC和C/.NET 两个EXE在如何与DLL交

我有一个c.NET多线程应用程序,它正在冻结接口。不寻常的是,界面不会冻结,除非我让系统闲置足够长的时间,让屏幕保护程序启动,这需要我重新输入密码以重新访问系统。当我成功输入密码后界面再次可见时,界面被锁定。只要我不让屏幕保护程序启动,界面就不会锁定

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

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

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

我发现,如果我向DLL内的线程添加代码,使其每隔30秒调用Application.DoEvents,接口将冻结约30秒,然后像正常一样恢复活动。 我想有什么东西阻塞了主线程,并迫使DoEvents启动,这似乎打破了锁,但我不知道是什么原因导致了锁

这个问题发生在我的开发机器和测试机器上

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

我已经做多线程编程多年了,从来没有见过这样的事情;因此,任何建议都将不胜感激


谢谢。

当您使用非标准方式初始化用户界面时,SystemEvents类通常会导致此问题。特别是使用线程。启动程序,调试+全部中断,调试+窗口+线程。如果您看到一个名为.NET SystemEvents的线程,那么您肯定会遇到这种挂起

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

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

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

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

当您使用非标准方式初始化用户界面时,SystemEvents类通常会导致此问题。特别是使用线程。启动程序,调试+全部中断,调试+窗口+线程。如果您看到一个名为.NET SystemEvents的线程,那么您肯定会遇到这种挂起

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

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

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

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

问题似乎与ActiveX控件在表单中的使用不正确有关。我转而使用.NET中的串行端口库,无法重现我的问题。感谢大家,特别是Hans的帮助。

问题似乎与ActiveX控件在表单中的使用不正确有关。我转而使用.NET中的串行端口库,无法重现我的问题。感谢所有人,尤其是汉斯的帮助。

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

我遇到的问题与我的电脑在屏幕保护程序启动或我锁定电脑且显示器进入睡眠状态时出现的问题相同。

我95%确信我的多线程应用程序中出现死锁。查看并确定代码中是否存在死锁。

在调试器中暂停冻结的UI并查看调用堆栈。您是否尝试过仅从非UI线程调用DLL方法并编组到UI线程?这可能不会完全有帮助,但是当屏幕保护程序启动时,你是否打开了任何节能开关?我认为这可能会使端口处于休眠状态。不管是什么,Application.DoEvents都不是答案。今天似乎无法在我的开发机器上使其失败。在调试器中暂停冻结的UI并查看调用堆栈。您是否尝试过仅从非UI线程调用DLL方法并编组到UI线程?这可能没有完全的帮助,但是当屏幕保护程序启动时,你是否打开了任何节能开关?我想这可能会使端口处于休眠状态。不管是什么,Application.DoEvents都不是答案。我现在似乎无法让它在我的开发机器上失败。我可以很容易地将其添加到调用此DLL的c/.NET应用程序中,但是对于调用此DLL的c++/MFC应用程序,我该怎么做?呃,调用初始化函数?C++代码是否正确初始化线程CONPROCELIZEX来选择STA?你最好在初始化函数中检查Thread.CurrentThread.GetApartmentState。我第一次进入DLL时检查了当前线程的单元状态,并将其设置为STA。在应用程序运行之前,我还将上面推荐的行添加到了我的C exe的主方法中。运行后没有任何区别。当我启动exe时,我打开主窗体的窗口,然后当用户单击一个按钮时,调用DLL打开com端口并启动线程。当用户选择要执行的模式时,exe再次调用DLL,打开一个状态窗口,然后警告DLL中的线程开始收集数据。您是否在DataReceived事件处理程序中正确使用BeginInvoke?这就是您的问题,这将使程序死锁。我看不到你的代码,很难诊断原因。重写表单中的OnHandleCreated方法,并在其上设置断点,以便查看它们是在哪个线程上创建的。使用相同的调试窗口。我可以很容易地将其添加到调用此DLL的c/.NET应用程序中,但是对于调用此DLL的c++/MFC应用程序,我该怎么做?呃,调用初始化函数?C++代码是否正确初始化线程CONPROCELIZEX来选择STA?你最好在初始化函数中检查Thread.CurrentThread.GetApartmentState。我第一次进入DLL时检查了当前线程的单元状态,并将其设置为STA。在应用程序运行之前,我还将上面推荐的行添加到了我的C exe的主方法中。运行后没有任何区别。当我启动exe时,我打开主窗体的窗口,然后当用户单击一个按钮时,调用DLL打开com端口并启动线程。当用户选择要执行的模式时,exe再次调用DLL,打开一个状态窗口,然后警告DLL中的线程开始收集数据。您是否在DataReceived事件处理程序中正确使用BeginInvoke?这就是您的问题,这将使程序死锁。我看不到你的代码,很难诊断原因。覆盖OnHandleCrea ted方法,并在其上设置一个断点,以便可以查看它们是在哪个线程上创建的。使用相同的调试窗口。