简体   繁体   English

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

[英]Interface freezes in multi-threaded c# application

I have ac# .NET multi-threaded application that is freezing the interface. 我有一个ac#.NET多线程应用程序,该应用程序冻结了接口。 What is unusual about this is that the interface does not freeze unless I let the system sit idle long enough for the screen saver to start (which requires me to reenter my password to re-gain access to the system). 与此不同的是,除非我让系统闲置足够长的时间以使屏幕保护程序能够启动,否则接口不会冻结(这需要我重新输入密码才能重新获得对系统的访问权限)。 When the interface becomes visible again (after I have successfully entered my password) the interface is locked up. 当界面再次变得可见时(在我成功输入密码之后),界面被锁定。 As long as I don't let the screensaver start, then the interface does not lockup. 只要我不启动屏幕保护程序,该界面就不会锁定。

I should point out that I have two different executables that access the same dll and this problem is occurring no matter which application I use to access the DLL. 我应该指出,我有两个访问同一个dll的不同可执行文件,无论我使用哪个应用程序访问DLL,都会出现此问题。 This seems to imply that the problem is in the DLL as the two applications are completely different (C++/MFC) and (C#/.NET) apart from how they relate to the DLL. 这似乎暗示问题出在DLL中,因为两个应用程序(C ++ / MFC)和(C#/。NET)完全不同,除了它们与DLL的关系如何。

Both exes perform similar steps in how they interact with the DLL. 两个exe在与DLL交互的方式上执行相似的步骤。 They make calls into the dll to setup the serial port communication, open a status window in the DLL, start a thread in the DLL to monitor the comm port, and then starts a thread in the main app that monitors a stack in the dll. 他们调用dll来设置串行端口通信,在DLL中打开一个状态窗口,在DLL中启动一个线程以监视通讯端口,然后在主应用程序中启动一个线程来监视dll中的堆栈。

When data is obtained from the comm port by the thread in the DLL, it is parsed and its results are placed on the stack and then posted to the status window via a delegate. 当DLL中的线程从通讯端口获取数据时,将对其进行解析,并将其结果放入堆栈中,然后通过委托将其发布到状态窗口中。 When the thread in the exe sees data in the stack, it outputs the data in the main window, also using a delegate. 当exe中的线程看到堆栈中的数据时,它也使用委托在主窗口中输出数据。

I found that if I add code to the thread inside the DLL so it calls Application.DoEvents() every 30 seconds, the interface will be frozen for about 30 seconds and then resume activity like normal. 我发现,如果我将代码添加到DLL中的线程中,以便每30秒调用一次Application.DoEvents(),该接口将被冻结大约30秒,然后像平常一样恢复活动。 I figure something is blocking the main thread and forcing DoEvents() to fire seems to break the lock, but I have no idea what might be causing this lock. 我认为有什么东西阻塞了主线程并迫使DoEvents()触发似乎打破了锁,但是我不知道是什么原因导致了该锁。

This issue occurs both on my development machine and on a test machine. 在我的开发计算机和测试计算机上均会发生此问题。

I have tried completely removing the output of data to the status window inside the DLL, but that didn't make any difference. 我尝试将数据输出完全删除到DLL内的状态窗口,但这没什么区别。

I have been doing multi-threaded programming for years and never seen anything like this; 我从事多线程编程已有多年了,从未见过这样的事情。 so any advice would be greatly appreciated. 因此,任何建议将不胜感激。

Thanks. 谢谢。

This is a problem that's commonly induced by the SystemEvents class when you have a non-standard way to initialize your user interface. 当您使用非标准方式初始化用户界面时,这是SystemEvents类通常引起的问题。 Using threads, specifically. 特别是使用线程。 Start your program, Debug + Break All, Debug + Windows + Threads. 启动程序,调试+全部破坏,调试+ Windows +线程。 If you see a thread named ".NET SystemEvents" then you're pretty much guaranteed to get this hang. 如果您看到一个名为“ .NET SystemEvents”的线程,那么您肯定可以将其挂起。

Some background: the SystemEvent class supports both console mode apps and GUI apps. 背景知识:SystemEvent类同时支持控制台模式应用程序和GUI应用程序。 For the latter, it should fire its event handlers on the UI thread. 对于后者,它应该在UI线程上触发其事件处理程序。 The very first time one of its events is subscribed, it creates a little invisible helper window to get the system notifications. 第一次订阅其事件之一时,它会创建一个不可见的帮助程序窗口以获取系统通知。 It can do this two ways, either by creating the window on the calling thread or by starting up a helper thread. 它可以通过在调用线程上创建窗口或启动帮助程序线程来完成这两种方式。 It makes the decision based on the value of Thread.GetApartmentState(). 它基于Thread.GetApartmentState()的值进行决策。 If it is STA then it can create the window on the calling thread and all event callbacks can be properly marshaled to that thread. 如果它是STA,则可以在调用线程上创建窗口,并且所有事件回调都可以正确编组到该线程。

This goes wrong if the first window you create is not created on the UI thread. 如果未在UI线程上创建您创建的第一个窗口,则会出错。 A splash screen for example. 例如启动画面。 That window may contain controls that are interested in a system event like UserPreferenceChanged so they can properly repaint themselves. 该窗口可能包含对系统事件感兴趣的控件,例如UserPreferenceChanged,以便它们可以正确地重新绘制自己。 It now uses the helper thread and any event will be fired from that helper thread, not the UI thread. 现在,它使用助手线程,并且将从该助手线程而不是UI线程触发任何事件。 Poison to any window that runs on the UI thread. 毒害在UI线程上运行的任何窗口。 The session switch out of a locked workstation (including the screen saver) is for some mysterious reason very likely to cause deadlock. 出于某种神秘的原因,从锁定的工作站(包括屏幕保护程序)中退出会话很可能导致死锁。 You may also see an occasional painting mishap, the less nasty result of using windows from the wrong thread. 您可能还会看到偶尔的绘画事故,这是使用错误线程中的窗口的较不愉快的结果。

Short from fixing the initialization order, a workaround is to put this in your Main() method, before any windows are created: 除了确定初始化顺序之外,一种变通方法是在创建任何窗口之前将其放入您的Main()方法中:

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

The problem does appear to be related to the ActiveX control is was probably using incorrectly in a form. 该问题确实与ActiveX控件有关,该ActiveX控件可能是在表格中使用不正确。 I switched to using the serial port library in .NET and have not been able to reproduce my problem. 我改用.NET中的串行端口库,但无法重现我的问题。 Thanks to everyone, especially Hans for their assistance. 感谢所有人,尤其是汉斯的帮助。

I am having the same issue as my PC just hangs up when the screen saver kicks off or I lock my PC and monitor goes to sleep. 我遇到了同样的问题,因为屏幕保护程序启动时我的PC只是挂起,或者我锁定了PC并且显示器进入睡眠状态。 I am 95% sure that there are deadlocks appearing in my multithreaded app. 我95%确信多线程应用程序中出现死锁。 Look and identify whether there are any deadlocks in your code. 查看并确定代码中是否存在任何死锁。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM