8


1

一晩実行するとWindowsフォームアプリケーションがランダムにフリーズする

ウィンドウフォームアプリケーションがあり、メインUIスレッドを呼び出してUIを更新する複数のスレッドが実行されています。 開発マシンでは、アプリケーションのメインUIスレッドの実行が停止し、アプリケーションが応答しなくなることがあります。 アプリケーションを一晩実行したままにしておくと発生するようです。 ただし、リモートデスクトップを介してこのウィンドウフォームアプリケーションを実行するユーザーがいるので、ユーザーの操作なしでアプリケーションを一晩実行したままにしておくと、この問題が頻繁に発生します。

articleがこの問題を説明しているようですが、アプリケーションがフリーズする理由を理解するのに十分なWindows開発知識がありません。

私が得た唯一の情報は、メインUIスレッドが何らかの操作を待っていることを示す、次のスタックトレースです。

この問題は、かなり長い間私を悩ませてきました。 提案やコメントをいただければ幸いです。

ありがとうございます。

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#

4 Answer


13


はい、これはSystemEventsクラスによって引き起こされる非常に悪名高いスレッドの問題です。 確かな診断結果は得られませんでしたが、90%の確率で、これはアプリの初期化の問題によって引き起こされます。

根本的な問題は、SystemEventsが生成するイベントに関心のあるコントロールを持つアプリの最初のフォームによってオンデマンドで初期化されることです。 その最初のフォームがメインスレッドで作成されていない場合、SystemEventsはプログラムのUIスレッドがどのスレッドであるかを推測することはできません。 最終的に、通知が受信されると(UserPreferenceChangingなど)、そのスレッドでイベントを発生させようとしますが、もう通知はありません。 SynchronizationContextクラスのフォールバックコードは、代わりにスレッドプールスレッドでイベントを発生させます。 これは、ウィンドウを作成しなかったスレッドでUIコードを実行することにより、必然的にThreading Hellを呼び出します。 それが起こると、多くのものがうまくいかないことがあります。 デッドロックは、ワークステーションがロックされた後にデスクトップを復元するときに特に一般的な結果です。

これがうまくいかない唯一の方法ではなく、別のスレッドでフォームを作成する場合は避けられません。 現在、SystemEventsはもちろん正しいスレッドでイベントを発生させることができないため、誰かが負けそうです。 デバッグ手法を示すブログ投稿https://blogs.msdn.microsoft.com/dsui_team/2012/10/31/debugging-windows-forms-application-hangs-during-systemevents-userpreferencechanged/ [こちら]。 はい、いです。 理想的には、コントロールはこれに対処し、通知自体をマーシャリングすることを知っています。 しかし、それは.NET 2.0で忘れられていた知識であり、DataGridView、NumericUpDown、DomainUpDown、ToolStrip + MenuStrip、およびToolStripItem派生クラスはこれを行いません。 RichTextBoxとProgressBarは疑わしいことに注意してください。残りは大丈夫です。

アプリの起動シーケンスを確認します。 独自のスプラッシュスクリーンを作成することは良いリードです。WindowsFormsApplicationBaseクラスが提供する組み込みサポートを使用してください。 自分でそれを行う場合は、ビットマップだけで非常にシンプルに保ちます。 また、前述のように、ワーカースレッドで独自のフォームを作成する可能性のある場所は、トラブルの原因となります。 常にその逆を行い、ワーカーで高価なコードを実行し、メインスレッドでUIを維持します。


6


私はこのまったく同じ問題を約1年前に経験しました(ユーザーインタラクションなしでしばらくすると、コールスタックに `OnUserPreferenceChanging()`でアプリケーションがハングします)。

最も可能性の高い原因は、メインフォームではなくコントロールで InvokeRequired /` Invoke() `を使用していることです。 これにより、コントロールのハンドルがまだ作成されていない場合、間違った結果が生成されることがあります。

解決策は、メインウィンドウで常に InvokeRequired /` Invoke() を呼び出すことです(フォームクラスに依存関係を導入したくない場合は、 ISynchronizeInvoke`としてキャストできます)。

原因と解決策の優れた、非常に詳細な説明を見つけることができますhttp://www.ikriv.com/en/prog/info/dotnet/MysteriousHang.html#WhatToDo[here]。


2


私はこれとまったく同じ問題に悩まされており、それは常にWindows 8.1で頻繁に発生するMicrosoft.Win32.SystemEvents.DisplaySettingsChangedイベントが原因であり、アプリケーションが実行されていて、VNCまたはRDPに接続されているときにも発生しました。 また、MacでFusion(VMWare)を使用してWindows x.xを使用すると、デスクトップ設定が時々変更されることも非常に明確でした。

多くのことを試した後、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に参加するのを待っていたときに抱えていたデッドロックを無効にしているようです。

お役に立てれば。


0


ビジュアルスタイルを無効にすると、問題も解決されます(必要ない場合)

//Comment this line if you do not want visual styles and do not want to mess with SystemEvents.
//Application.EnableVisualStyles();