Windows Form应用程序在运行过夜时会随机冻结

我有一个窗口窗体应用程序,它有多个线程运行,将调用主UI线程来更新用户界面。 偶尔在开发机器上,应用程序主UI线程将停止运行,应用程序不再响应。 如果我让应用程序在一夜之间运行,似乎就会发生。 不过,我有用户通过远程桌面运行这个窗口窗体应用程序,如果应用程序在一夜之间没有用户交互的情况下运行,这个问题会更频繁地发生。

我发现一篇文章似乎正在描述这个问题,但我没有足够的Windows开发知识来弄清楚为什么应用程序会冻结。

我得到的唯一信息是以下堆栈跟踪,指示主UI线程正在等待某种操作。

这个问题已经困扰了我很长一段时间了。 我将不胜感激任何build议或意见。

谢谢!

主UI线程堆栈跟踪:

 mscorlib.dll!System.Threading.WaitHandle.WaitOne(超时,bool exitContext)+ 0x2f字节
 mscorlib.dll!System.Threading.WaitHandle.WaitOne(int millisecondsTimeout,bool exitContext)+ 0x25字节
 System.Windows.Forms.dll!System.Windows.Forms.Control.WaitForWaitHandle(System.Threading.WaitHandle waitHandle = {System.Threading.ManualResetEvent})4268行C#
 System.Windows.Forms.dll!System.Windows.Forms.Control.MarshaledInvoke(System.Windows.Forms.Control调用方,System.Delegate方法,object [] args,bool同步)第7614行C#
 System.Windows.Forms.dll!System.Windows.Forms.Control.Invoke(System.Delegate方法,object [] args)行7178 + 0x11字节C#
 System.Windows.Forms.dll!System.Windows.Forms.WindowsFormsSynchronizationContext.Send(System.Threading.SendOrPostCallback d,对象状态)第89行C#
 System.dll!Microsoft.Win32.SystemEvents.SystemEventInvokeInfo.Invoke(bool checkFinalization = true,object [] args = {object [2]})+ 0x62字节
 System.dll!Microsoft.Win32.SystemEvents.RaiseEvent(bool checkFinalization = true,object key = {object},object [] args = {object [2]})+ 0x10f字节
 System.dll!Microsoft.Win32.SystemEvents.OnUserPreferenceChanging(int msg,System.IntPtr wParam,System.IntPtr lParam)+ 0x77字节
 System.dll!Microsoft.Win32.SystemEvents.WindowProc(System.IntPtr hWnd = 2032836,int msg = 8218,System.IntPtr wParam = 47,System.IntPtr lParam = 100019840)+ 0x2ca字节
 [原生到托pipe转换]
 [pipe理到本地过渡]
 System.Windows.Forms.dll!System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(int dwComponentID,int reason = 4,int pvLoopData = 0)行2106 + 0x8字节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字节C#
 System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoop(int reason,System.Windows.Forms.ApplicationContext context)行3261 + 0xa字节C#
 System.Windows.Forms.dll!System.Windows.Forms.Application.RunDialog(System.Windows.Forms.Form窗体)1488行C#
 System.Windows.Forms.dll!System.Windows.Forms.Form.ShowDialog(System.Windows.Forms.IWin32Window owner)行6120 + 0x8字节C#
 Schedule.exe!ME.APTS.ScheduleApp.ScheduleAppMainForm.ShowOpenScheduleForm.AnonymousMethod()第829行+ 0xd字节C#
 Schedule.exe!ME.APTS.ScheduleApp.ScheduleAppMainForm.PromptUserToSaveSchedule(System.Action oAfterPromptUserToSaveCallBack = {Method =无法评估expression式,因为当前方法的代码已被优化})行1858 + 0xb字节C#
 Schedule.exe!ME.APTS.ScheduleApp.ScheduleAppMainForm.ShowOpenScheduleForm()行859 + 0xb字节C#
 [原生到托pipe转换]
 [pipe理到本地过渡]
 mscorlib.dll!System.Delegate.DynamicInvokeImpl(object [] args)+ 0x55字节
 System.Windows.Forms.dll!System.Windows.Forms.Control.InvokeMarshaledCallbackDo(System.Windows.Forms.Control.ThreadMethodEntry tme)行7266 + 0xb字节C#
 System.Windows.Forms.dll!System.Windows.Forms.Control.InvokeMarshaledCallbackHelper(object obj)行7228 + 0x7字节C#
 mscorlib.dll!System.Threading.ExecutionContext.runTryCode(object userData)+ 0x51字节
 [原生到托pipe转换]
 [pipe理到本地过渡]
 mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext,System.Threading.ContextCallbackcallback,对象状态)+ 0x67字节
 mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext,System.Threading.ContextCallbackcallback,对象状态)+ 0x45字节
 System.Windows.Forms.dll!System.Windows.Forms.Control.InvokeMarshaledCallback(System.Windows.Forms.Control.ThreadMethodEntry tme)行7213 + 0xffffffc5字节C#
 System.Windows.Forms.dll!System.Windows.Forms.Control.InvokeMarshaledCallbacks()行7297 + 0xb字节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)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)7515行C#
 System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.OnMessage(ref System.Windows.Forms.Message m)行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)行647 + 0xa字节C#
 System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.DefWndProc(ref System.Windows.Forms.Message m = {System.Windows.Forms.Message})行814 + 0x1d字节C#
 System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.WndProc(ref System.Windows.Forms.Message m)行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字节
 System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.Callback(System.IntPtr hWnd,int msg = 49512,System.IntPtr wparam,System.IntPtr lparam)行647 + 0xa字节C#
 [原生到托pipe转换]
 [pipe理到本地过渡]
 System.Windows.Forms.dll!System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(int dwComponentID,int reason = -1,int pvLoopData = 0)行2106 + 0x8字节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)行3261 + 0xa字节C#
 System.Windows.Forms.dll!System.Windows.Forms.Application.Run()1457行C#
 Schedule.exe!ME.APTS.ScheduleApp.ScheduleApp.LoadData()行318 + 0x5字节C#
 Schedule.exe!ME.APTS.ScheduleApp.ScheduleApp.Run()行170 + 0x9字节C#
 Schedule.exe!ME.APTS.ScheduleApp.ScheduleApp.Main()行126 + 0xb字节C#

我在一年前遇到过这个完全相同的问题(应用程序在没有用户交互的情况下挂起,在调用堆栈中使用OnUserPreferenceChanging() )。

最可能的原因是您在控件上使用InvokeRequired / Invoke() ,而不是在主窗体上。 如果控件的句柄尚未创建,有时会产生错误的结果。

解决方法是在主窗口上始终调用InvokeRequired / Invoke() (如果不想为表单类引入依赖项,则可以将其作为ISynchronizeInvoke )。

你可以在这里找到一个很好的,非常详细的原因和解决方案的描述。

是的,这是由SystemEvents类造成的一个相当臭名昭着的线程问题。 我从来没有得到一个坚实的诊断,但90%的可能性是,这是由您的应用程序中的初始化问题触发。

根本问题是SystemEvent按照您的应用程序中的第一种形式进行按需初始化,该控件对其生成的事件感兴趣。 如果没有在主线程中创建第一个表单,那么SystemEvents无法猜测程序中哪个线程是UI线程。 最终,当收到通知(如UserPreferenceChanging)时,它会尝试在该线程上触发事件,但不在其周围。 SynchronizationContext类中的回退代码会引发线程池线程上的事件。 这不可避免地通过在没有创建窗口的线程上运行UI代码来调用线程地狱(Threading Hell)。 发生这种情况时,很多事情可能会出错。 在工作站锁定后恢复桌面时,死锁是特别常见的结果。

不是唯一可能出现这种情况的方法,如果您在另一个线程上创建任何表单,这是不可避免的。 现在SystemEvent当然不可能在正确的线程上引发事件,有人会输。 展示调试技术的博客文章就在这里 。 是的,丑陋的 理想情况下,控制人员知道要处理这个事情,并且编组通知本身。 但是这是在.NET 2.0,DataGridView,NumericUpDown,DomainUpDown,ToolStrip + MenuStrip和ToolStripItem派生类忘记知识不这样做。 我应该注意RichTextBox和ProgressBar是可疑的,其余的都没关系。

查看您的应用程序的启动顺序。 创建你自己的启动画面是一个很好的主角,不妨使用WindowsFormsApplicationBase类提供的内置支持。 如果你自己做,那么保持简单,只是一个位图。 如前所述,任何可以在工作线程上创建自己的表单的地方都是一个麻烦的处方。 总是这样做,在工作人员上运行昂贵的代码,并将UI保留在主线程上。

我一直在遭受这个完全相同的问题,这总是由于Windows 8.1下更频繁地发生Microsoft.Win32.SystemEvents.DisplaySettingsChanged事件,也是因为我的应用程序正在运行,并且有人连接了VNC或RDP。 在Windows上使用Windows xx和Fusion(VMWare)时,也会非常清楚地改变桌面设置。

在尝试了很多事情之后,我终于通过在MainApp中侦听这些事件(创建所有对话框并执行所有Invoke)来解决这个问题。

宣布:

 Microsoft.Win32.SystemEvents.DisplaySettingsChanged += SystemEvents_DisplaySettingsChanged; Microsoft.Win32.SystemEvents.DisplaySettingsChanging += SystemEvents_DisplaySettingsChanging; Microsoft.Win32.SystemEvents.UserPreferenceChanged += SystemEvents_UserPreferenceChanged; 

实行:

 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 } 

这些事件的捕获什么都不做,但是这似乎是排除了当这些事件来自窗口,而我的代码的任何其他部分正在等待MainApp参加一个Invoke的时候遇到的僵局。

希望这可以帮助。