Windows 窗体应用程序在夜间运行时随机冻结
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3832156/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Windows Form application freeze randomly when run overnight
提问by dsum
I have a window form application, and it has multiple threads running that would invoke on the Main UI thread to update the UI. Occasionally on development machine, the application main UI thread will stop running, and the application no longer responses. It seems to happen if I left the application running overnight. However, I have users who run this window form application though remote desktop, and this problem happen a lot more often if the application is left running overnight with no user interaction.
我有一个窗口窗体应用程序,它有多个线程在运行,这些线程会在主 UI 线程上调用以更新 UI。偶尔在开发机器上,应用程序主 UI 线程会停止运行,应用程序不再响应。如果我让应用程序在一夜之间运行,似乎会发生这种情况。但是,我有用户通过远程桌面运行此窗口窗体应用程序,如果应用程序在没有用户交互的情况下在一夜之间运行,则此问题会更频繁地发生。
I have find an articleseems to be describing this problem, but I don't have enough Windows development knowledge to figure out why the application would freeze.
我发现一篇文章似乎在描述这个问题,但我没有足够的 Windows 开发知识来弄清楚为什么应用程序会冻结。
The only information I got is the following stack trace, indicating the main UI thread is waiting for some kind of operation.
我得到的唯一信息是以下堆栈跟踪,表明主 UI 线程正在等待某种操作。
This problem has been bothering me for quite some time now. I would appreciate any suggestions or comments.
这个问题已经困扰我很长时间了。我将不胜感激任何建议或意见。
Thanks!
谢谢!
Main UI thread stack trace: mscorlib.dll!System.Threading.WaitHandle.WaitOne(long timeout, bool exitContext) + 0x2f bytes mscorlib.dll!System.Threading.WaitHandle.WaitOne(int millisecondsTimeout, bool exitContext) + 0x25 bytes System.Windows.Forms.dll!System.Windows.Forms.Control.WaitForWaitHandle(System.Threading.WaitHandle waitHandle = {System.Threading.ManualResetEvent}) Line 4268 C# System.Windows.Forms.dll!System.Windows.Forms.Control.MarshaledInvoke(System.Windows.Forms.Control caller, System.Delegate method, object[] args, bool synchronous) Line 7614 C# System.Windows.Forms.dll!System.Windows.Forms.Control.Invoke(System.Delegate method, object[] args) Line 7178 + 0x11 bytes C# System.Windows.Forms.dll!System.Windows.Forms.WindowsFormsSynchronizationContext.Send(System.Threading.SendOrPostCallback d, object state) Line 89 C# System.dll!Microsoft.Win32.SystemEvents.SystemEventInvokeInfo.Invoke(bool checkFinalization = true, object[] args = {object[2]}) + 0x62 bytes System.dll!Microsoft.Win32.SystemEvents.RaiseEvent(bool checkFinalization = true, object key = {object}, object[] args = {object[2]}) + 0x10f bytes System.dll!Microsoft.Win32.SystemEvents.OnUserPreferenceChanging(int msg, System.IntPtr wParam, System.IntPtr lParam) + 0x77 bytes System.dll!Microsoft.Win32.SystemEvents.WindowProc(System.IntPtr hWnd = 2032836, int msg = 8218, System.IntPtr wParam = 47, System.IntPtr lParam = 100019840) + 0x2ca bytes [Native to Managed Transition] [Managed to Native Transition] System.Windows.Forms.dll!System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(int dwComponentID, int reason = 4, int pvLoopData = 0) Line 2106 + 0x8 bytes C# System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(int reason = 4, System.Windows.Forms.ApplicationContext context = {System.Windows.Forms.Application.ModalApplicationContext}) Line 3377 + 0x1b bytes C# System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoop(int reason, System.Windows.Forms.ApplicationContext context) Line 3261 + 0xa bytes C# System.Windows.Forms.dll!System.Windows.Forms.Application.RunDialog(System.Windows.Forms.Form form) Line 1488 C# System.Windows.Forms.dll!System.Windows.Forms.Form.ShowDialog(System.Windows.Forms.IWin32Window owner) Line 6120 + 0x8 bytes C# Schedule.exe!ME.APTS.ScheduleApp.ScheduleAppMainForm.ShowOpenScheduleForm.AnonymousMethod() Line 829 + 0xd bytes C# Schedule.exe!ME.APTS.ScheduleApp.ScheduleAppMainForm.PromptUserToSaveSchedule(System.Action oAfterPromptUserToSaveCallBack = {Method = Cannot evaluate expression because the code of the current method is optimized.}) Line 1858 + 0xb bytes C# Schedule.exe!ME.APTS.ScheduleApp.ScheduleAppMainForm.ShowOpenScheduleForm() Line 859 + 0xb bytes C# [Native to Managed Transition] [Managed to Native Transition] mscorlib.dll!System.Delegate.DynamicInvokeImpl(object[] args) + 0x55 bytes System.Windows.Forms.dll!System.Windows.Forms.Control.InvokeMarshaledCallbackDo(System.Windows.Forms.Control.ThreadMethodEntry tme) Line 7266 + 0xb bytes C# System.Windows.Forms.dll!System.Windows.Forms.Control.InvokeMarshaledCallbackHelper(object obj) Line 7228 + 0x7 bytes C# mscorlib.dll!System.Threading.ExecutionContext.runTryCode(object userData) + 0x51 bytes [Native to Managed Transition] [Managed to Native Transition] mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) + 0x67 bytes mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) + 0x45 bytes System.Windows.Forms.dll!System.Windows.Forms.Control.InvokeMarshaledCallback(System.Windows.Forms.Control.ThreadMethodEntry tme) Line 7213 + 0xffffffc5 bytes C# System.Windows.Forms.dll!System.Windows.Forms.Control.InvokeMarshaledCallbacks() Line 7297 + 0xb bytes C# System.Windows.Forms.dll!System.Windows.Forms.Control.WndProc(ref System.Windows.Forms.Message m) Line 13848 C# System.Windows.Forms.dll!System.Windows.Forms.ScrollableControl.WndProc(ref System.Windows.Forms.Message m) Line 1491 C# System.Windows.Forms.dll!System.Windows.Forms.ContainerControl.WndProc(ref System.Windows.Forms.Message m) Line 1898 C# System.Windows.Forms.dll!System.Windows.Forms.Form.WndProc(ref System.Windows.Forms.Message m) Line 7515 C# System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.OnMessage(ref System.Windows.Forms.Message m) Line 14051 C# System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.WndProc(ref System.Windows.Forms.Message m) Line 14106 C# System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.Callback(System.IntPtr hWnd, int msg = 49512, System.IntPtr wparam, System.IntPtr lparam) Line 647 + 0xa bytes C# System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.DefWndProc(ref System.Windows.Forms.Message m = {System.Windows.Forms.Message}) Line 814 + 0x1d bytes C# System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.WndProc(ref System.Windows.Forms.Message m) Line 1409 C# Infragistics2.Win.UltraWinToolbars.v8.1.dll!Infragistics.Win.UltraWinToolbars.UltraToolbarsManager.FormSubClasser.WndProcImpl(ref System.Windows.Forms.Message m) + 0x17f5 bytes Infragistics2.Win.UltraWinToolbars.v8.1.dll!Infragistics.Win.UltraWinToolbars.UltraToolbarsManager.FormSubClasser.WndProc(ref System.Windows.Forms.Message m) + 0x5 bytes System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.Callback(System.IntPtr hWnd, int msg = 49512, System.IntPtr wparam, System.IntPtr lparam) Line 647 + 0xa bytes C# [Native to Managed Transition] [Managed to Native Transition] System.Windows.Forms.dll!System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(int dwComponentID, int reason = -1, int pvLoopData = 0) Line 2106 + 0x8 bytes C# System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(int reason = -1, System.Windows.Forms.ApplicationContext context = {System.Windows.Forms.ApplicationContext}) Line 3377 + 0x1b bytes C# System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoop(int reason, System.Windows.Forms.ApplicationContext context) Line 3261 + 0xa bytes C# System.Windows.Forms.dll!System.Windows.Forms.Application.Run() Line 1457 C# Schedule.exe!ME.APTS.ScheduleApp.ScheduleApp.LoadData() Line 318 + 0x5 bytes C# Schedule.exe!ME.APTS.ScheduleApp.ScheduleApp.Run() Line 170 + 0x9 bytes C# Schedule.exe!ME.APTS.ScheduleApp.ScheduleApp.Main() Line 126 + 0xb bytes C#
采纳答案by matiash
I experienced this exact same issue about a year ago (application hang after some time without user interaction, with OnUserPreferenceChanging()
in the call stack).
大约一年前,我遇到了这个完全相同的问题(应用程序在没有用户交互的情况下OnUserPreferenceChanging()
在调用堆栈中挂起一段时间后挂起)。
The most likely cause is that you're using InvokeRequired
/Invoke()
on a control and not on the main form. This sometimes produces the wrong result if the control's handle hasn't been created yet.
最可能的原因是您在控件上而不是在主窗体上使用InvokeRequired
/ Invoke()
。如果尚未创建控件的句柄,这有时会产生错误的结果。
The solution is to always call InvokeRequired
/Invoke()
on the Main Window (which you can cast as an ISynchronizeInvoke
if you don't want to introduce a dependency to your form class).
解决方案是始终在主窗口上调用InvokeRequired
/ Invoke()
(ISynchronizeInvoke
如果您不想为表单类引入依赖项,则可以将其转换为 an )。
You can find an excellent, very detailed description of the cause and solution here.
您可以在此处找到对原因和解决方案的出色、非常详细的描述。
回答by Hans Passant
Yes, this is a fairly infamous threading problem caused by the SystemEvents class. I never got a solid diagnostic for it but the 90% odds are that this is triggered by an initialization problem in your app.
是的,这是一个由 SystemEvents 类引起的臭名昭著的线程问题。我从来没有得到可靠的诊断,但 90% 的可能性是这是由您的应用程序中的初始化问题触发的。
The root problem is that SystemEvents gets initialized on-demand by the first form in your app that has controls that are interested in the events it generates. If that first form is notcreated in the main thread then SystemEvents is helpless to guess at which thread is the UI thread in your program. Eventually, when a notification is received (like UserPreferenceChanging), it tries to fire the event on that thread, but it isn't around anymore. The fallback code in the SynchronizationContext class raises the event on a threadpool thread instead. That inevitably invokes Threading Hell by running UI code on a thread that didn't create the window. Lots of things can go wrong when that happens. Deadlock is a particularly common outcome when restoring the desktop after the workstation was locked.
根本问题是 SystemEvents 由应用程序中的第一个表单按需初始化,该表单具有对其生成的事件感兴趣的控件。如果第一个表单不是在主线程中创建的,那么 SystemEvents 无法猜测哪个线程是您程序中的 UI 线程。最终,当收到通知(如 UserPreferenceChanging)时,它会尝试在该线程上触发事件,但它不再存在。SynchronizationContext 类中的回退代码在线程池线程上引发事件。这不可避免地通过在未创建窗口的线程上运行 UI 代码来调用线程地狱。当这种情况发生时,很多事情都会出错。在工作站被锁定后恢复桌面时,死锁是一种特别常见的结果。
Not the only possible way this can go wrong, it is inevitable if you create any form on another thread. Now SystemEvents cannot possibly raise the event on the correct thread of course, somebody is going to lose. A blog post that demonstrates a debugging technique is here. Yes, ugly. Ideally a control knows to deal with this and marshal the notification itself. But that was forgotten knowledge at .NET 2.0, DataGridView, NumericUpDown, DomainUpDown, ToolStrip+MenuStrip and the ToolStripItem derived classes don't do this. I should note that RichTextBox and ProgressBar are suspicious, the rest are okay.
这不是唯一可能出错的方式,如果您在另一个线程上创建任何表单,这是不可避免的。现在 SystemEvents 不可能在正确的线程上引发事件,当然有人会失败。演示调试技术的博客文章在这里。是的,丑。理想情况下,控件知道处理这个问题并编组通知本身。但在 .NET 2.0 中这被遗忘了,DataGridView、NumericUpDown、DomainUpDown、ToolStrip+MenuStrip 和 ToolStripItem 派生类不这样做。我应该注意到 RichTextBox 和 ProgressBar 是可疑的,其余的没问题。
Review the startup sequence of your app. Creating your own splash screen is a good lead, do favor using the built-in support that the WindowsFormsApplicationBase class provides. If you do it yourself then keep it very simple, just a bitmap. And as noted, any place where you might create your own form on a worker thread is a recipe for trouble. Always do it the other way around, run the expensive code on a worker and keep the UI on the main thread.
查看应用程序的启动顺序。创建您自己的启动画面是一个很好的引导,请使用 WindowsFormsApplicationBase 类提供的内置支持。如果你自己做,那么保持它非常简单,只是一个位图。如前所述,任何您可以在工作线程上创建自己的表单的地方都会带来麻烦。总是反过来做,在工作线程上运行昂贵的代码并将 UI 保留在主线程上。
回答by Luis Otero
I have been suffering this exact same problem and it was always due to the Microsoft.Win32.SystemEvents.DisplaySettingsChanged event that happens way more frequently under Windows 8.1 and also also when my application was running and someone connected with VNC or RDP. It was also very clear when using Windows x.x with Fusion (VMWare) over Mac that changes the desktop settings from time to time.
我一直在遇到这个完全相同的问题,这总是由于 Microsoft.Win32.SystemEvents.DisplaySettingsChanged 事件在 Windows 8.1 下更频繁地发生,而且当我的应用程序正在运行并且有人与 VNC 或 RDP 连接时也是如此。在 Mac 上使用 Windows xx 和 Fusion (VMWare) 时,它会不时更改桌面设置,这一点也很明显。
After trying lot of things I finally got it resolving by listening these events in my MainApp (the one that create all dialogs and also perform all Invoke)
在尝试了很多事情之后,我终于通过在我的 MainApp(创建所有对话框并执行所有 Invoke 的那个)中监听这些事件来解决它
Declare:
宣布:
Microsoft.Win32.SystemEvents.DisplaySettingsChanged += SystemEvents_DisplaySettingsChanged;
Microsoft.Win32.SystemEvents.DisplaySettingsChanging += SystemEvents_DisplaySettingsChanging;
Microsoft.Win32.SystemEvents.UserPreferenceChanged += SystemEvents_UserPreferenceChanged;
Implement:
实施:
static void SystemEvents_UserPreferenceChanged(object sender, Microsoft.Win32.UserPreferenceChangedEventArgs e)
{
//Do nothing
}
static void SystemEvents_DisplaySettingsChanged(object sender, EventArgs e)
{
//Do nothing
}
static void SystemEvents_DisplaySettingsChanging(object sender, EventArgs e)
{
//Do nothing
}
The capture of these events do nothing but this seems to be voiding the deadlock I was having when these events were coming from windows and any other part of my code was waiting for MainApp to attend an Invoke.
这些事件的捕获什么都不做,但这似乎可以消除当这些事件来自 Windows 并且我的代码的任何其他部分正在等待 MainApp 参与调用时我遇到的僵局。
Hope this helps.
希望这可以帮助。
回答by Luis Otero
Disabling the visual styles will also fix the issue (if you do not need them)
禁用视觉样式也将解决问题(如果您不需要它们)
//Comment this line if you do not want visual styles and do not want to mess with SystemEvents.
//Application.EnableVisualStyles();