本文介绍了接口在多线程C#应用程序中冻结的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个C#.NET多线程应用程序,该应用程序冻结了接口.与此不同的是,除非我让系统闲置足够长的时间以使屏幕保护程序能够启动(这要求我重新输入密码才能重新获得对系统的访问权限),否则接口不会冻结.当界面再次变得可见时(在我成功输入密码之后),界面被锁定.只要我不启动屏幕保护程序,该界面就不会锁定.

I have a c# .NET multi-threaded application that is freezing the interface. 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.

我应该指出,我有两个访问相同dll的不同可执行文件,无论我使用哪个应用程序访问DLL,都会出现此问题.这似乎暗示问题出在DLL中,因为两个应用程序(C ++/MFC)和(C#/.NET)完全不同,除了它们与DLL的关系如何.

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. 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.

两个exe在与DLL交互的方式上执行相似的步骤.他们调用dll来设置串行端口通信,在DLL中打开一个状态窗口,在DLL中启动一个线程以监视通讯端口,然后在主应用程序中启动一个线程来监视dll中的堆栈.

Both exes perform similar steps in how they interact with the 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中的线程从通讯端口获取数据时,将对其进行解析,并将其结果放入堆栈中,然后通过委托将其发布到状态窗口中.当exe中的线程看到堆栈中的数据时,它也会使用委托在主窗口中输出数据.

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. When the thread in the exe sees data in the stack, it outputs the data in the main window, also using a delegate.

我发现,如果我将代码添加到DLL内的线程中,从而每30秒调用一次Application.DoEvents(),该接口将被冻结大约30秒,然后像往常一样恢复活动.我发现有什么东西阻塞了主线程并迫使DoEvents()触发似乎打破了锁定,但我不知道是什么原因导致了该锁定.

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.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.

此问题在我的开发计算机和测试计算机上均会发生.

This issue occurs both on my development machine and on a test machine.

我尝试将数据输出完全删除到DLL内的状态窗口,但这没什么区别.

I have tried completely removing the output of data to the status window inside the DLL, but that didn't make any difference.

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

I have been doing multi-threaded programming for years and never seen anything like this; so any advice would be greatly appreciated.

谢谢.

推荐答案

当您使用非标准方式初始化用户界面时,这是SystemEvents类通常引起的问题.特别是使用线程.启动程序,调试+全部破坏,调试+ Windows +线程.如果您看到一个名为".NET SystemEvents"的线程,那么您肯定可以将其挂起.

This is a problem that's commonly induced by the SystemEvents class when you have a non-standard way to initialize your user interface. Using threads, specifically. Start your program, Debug + Break All, Debug + Windows + Threads. If you see a thread named ".NET SystemEvents" then you're pretty much guaranteed to get this hang.

某些背景:SystemEvent类同时支持控制台模式应用程序和GUI应用程序.对于后者,它应该在UI线程上触发其事件处理程序.第一次预订其事件之一时,它会创建一个不可见的帮助程序窗口以获取系统通知.它可以通过在调用线程上创建窗口或启动帮助程序线程来完成这两种方式.它基于Thread.GetApartmentState()的值进行决策.如果它是STA,则可以在调用线程上创建窗口,并且所有事件回调都可以正确地编组到该线程.

Some background: the SystemEvent class supports both console mode apps and GUI apps. For the latter, it should fire its event handlers on the UI thread. 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(). 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.

如果未在UI线程上创建您创建的 first 窗口,则会出错.例如启动画面.该窗口可能包含对系统事件感兴趣的控件,例如UserPreferenceChanged,以便它们可以正确地重新绘制自己.现在,它使用帮助程序线程,并且将从该帮助程序线程而不是UI线程中触发任何事件.毒害在UI线程上运行的任何窗口.出于某种神秘的原因,从锁定的工作站(包括屏幕保护程序)中退出会话很可能导致死锁.您可能还会看到偶尔的绘画事故,这是使用来自错误线程的窗口带来的较不愉快的结果.

This goes wrong if the first window you create is not created on the UI thread. 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. It now uses the helper thread and any event will be fired from that helper thread, not the UI thread. Poison to any window that runs on the UI thread. 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.

不固定初始化顺序,一种解决方法是在创建任何窗口之前,将其放入Main()方法中.

Short from fixing the initialization order, a workaround is to put this in your Main() method, before any windows are created:

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

这篇关于接口在多线程C#应用程序中冻结的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-13 01:44