Приложение Windows Form зависает случайным образом при запуске в течение ночи - PullRequest
8 голосов
/ 30 сентября 2010

У меня есть приложение в форме окна, и в нем запущено несколько потоков, которые будут вызывать поток основного пользовательского интерфейса для обновления пользовательского интерфейса. Иногда на компьютере разработчика основной поток пользовательского интерфейса приложения останавливается, и приложение больше не отвечает. Кажется, это произойдет, если я оставлю приложение работающим на ночь. Однако у меня есть пользователи, которые запускают это приложение в форме окна через удаленный рабочий стол, и эта проблема встречается гораздо чаще, если приложение остается запущенным на ночь без вмешательства пользователя.

Я обнаружил, что статья , похоже, описывает эту проблему, но у меня недостаточно знаний для разработки Windows, чтобы понять, почему приложение зависло.

Единственная информация, которую я получил, - это следующая трассировка стека, указывающая, что основной поток пользовательского интерфейса ожидает какую-то операцию.

Эта проблема беспокоит меня уже довольно давно. Буду признателен за любые предложения или комментарии.

Спасибо!

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 ]

13 голосов
/ 30 сентября 2010

Да, это довольно печально известная проблема с многопоточностью, вызванная классом SystemEvents. Я никогда не получал точного диагноза, но вероятность того, что это вызвано проблемой инициализации в вашем приложении, составляет 90%.

Основная проблема заключается в том, что SystemEvents инициализируется по требованию первой формой в вашем приложении, в которой есть элементы управления, которые заинтересованы в генерируемых событиях. Если эта первая форма не создана в главном потоке, то SystemEvents беспомощно угадать, какой поток является потоком пользовательского интерфейса в вашей программе. В конце концов, когда уведомление получено (например, UserPreferenceChanging), оно пытается запустить событие в этом потоке, но его больше нет. Резервный код в классе SynchronizationContext вместо этого вызывает событие в потоке потоков. Это неизбежно вызывает Threading Hell путем запуска кода пользовательского интерфейса в потоке, который не создал окно. Многие вещи могут пойти не так, когда это произойдет. Взаимная блокировка является особенно распространенным результатом при восстановлении рабочего стола после блокировки рабочей станции.

Не единственный возможный способ, которым это может пойти не так, это неизбежно, если вы создаете какую-либо форму в другом потоке. Теперь SystemEvents не может вызвать событие в нужном потоке, конечно, кто-то может проиграть. Сообщение в блоге, демонстрирующее методику отладки , находится здесь . Да, некрасиво В идеале элемент управления знает, как с этим справиться, и направляет само уведомление. Но это были забытые знания в .NET 2.0, DataGridView, NumericUpDown, DomainUpDown, ToolStrip + MenuStrip и производные классы ToolStripItem не делают этого. Должен отметить, что RichTextBox и ProgressBar являются подозрительными, с остальными все в порядке.

Просмотрите последовательность запуска вашего приложения. Создание собственного экрана-заставки - хороший пример, пользуйтесь встроенной поддержкой, предоставляемой классом WindowsFormsApplicationBase. Если вы делаете это сами, то сделайте это очень просто, просто растровое изображение. И, как уже отмечалось, любое место, где вы можете создать свою собственную форму в рабочем потоке, - это повод для неприятностей. Всегда делайте это наоборот, запускайте дорогой код на рабочем месте и сохраняйте пользовательский интерфейс в основном потоке.

7 голосов
/ 30 сентября 2010

Я столкнулся с такой же проблемой около года назад (зависание приложения через некоторое время без взаимодействия с пользователем, с OnUserPreferenceChanging() в стеке вызовов).

Наиболее вероятной причиной является то, что вы используете InvokeRequired / Invoke() в элементе управления, а не в главной форме. Иногда это приводит к неверному результату, если дескриптор элемента управления еще не создан.

Решение состоит в том, чтобы всегда вызывать InvokeRequired / Invoke() в главном окне (которое можно привести как ISynchronizeInvoke, если вы не хотите вводить зависимость для своего класса формы).

Отличное, очень подробное описание причины и решения здесь .

2 голосов
/ 14 августа 2015

У меня была точно такая же проблема, и это всегда было связано с событием Microsoft.Win32.SystemEvents.DisplaySettingsChanged, которое происходит намного чаще в Windows 8.1, а также во время работы моего приложения, когда кто-то подключался к VNC или RDP. Это также было очень ясно при использовании Windows x.x с Fusion (VMWare) поверх Mac, который время от времени изменяет настройки рабочего стола.

После многих попыток я, наконец, получил разрешение, прослушав эти события в моем MainApp (тот, который создает все диалоги, а также выполняет все Invoke)

Declare:

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 голосов
/ 27 февраля 2018

Отключение визуальных стилей также исправит проблему (если они вам не нужны)

//Comment this line if you do not want visual styles and do not want to mess with SystemEvents.
//Application.EnableVisualStyles();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...