Приложение WPF блокируется при обращении к диспетчеру - PullRequest
14 голосов
/ 14 февраля 2012

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

Может кто-нибудь предложить способы, чтобы я мог выяснить, что вызывает тупик?

Стек диспетчера следует и не выглядит необычным:

*0. System.Windows.Threading.DispatcherSynchronizationContext.Wait (source line information unavailable)

 1. System.Threading.SynchronizationContext.InvokeWaitMethodHelper (source line information unavailable)
 2. Xceed.Wpf.DataGrid.DeferredOperationManager.Process (source line information unavailable)
 3. Xceed.Wpf.DataGrid.DeferredOperationManager.Dispatched_Process (source line information unavailable)
 4. System.Windows.Threading.ExceptionWrapper.InternalRealCall (source line information unavailable)
 5. System.Windows.Threading.ExceptionWrapper.TryCatchWhen (source line information unavailable)
 6. System.Windows.Threading.Dispatcher.WrappedInvoke (source line information unavailable)
 7. System.Windows.Threading.DispatcherOperation.InvokeImpl (source line information unavailable)
 8. System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext (source line information unavailable)
 9. System.Threading.ExecutionContext.runTryCode (source line information unavailable)
 10. System.Threading.ExecutionContext.RunInternal (source line information unavailable)
 11. System.Threading.ExecutionContext.Run (source line information unavailable)
 12. System.Windows.Threading.DispatcherOperation.Invoke (source line information unavailable)
 13. System.Windows.Threading.Dispatcher.ProcessQueue (source line information unavailable
 14. System.Windows.Threading.Dispatcher.WndProcHook (source line information unavailable)
 15. MS.Win32.HwndWrapper.WndProc (source line information unavailable)
 16. MS.Win32.HwndSubclass.DispatcherCallbackOperation (source line information unavailable)
 17. System.Windows.Threading.ExceptionWrapper.InternalRealCall (source line information unavailable)
 18. System.Windows.Threading.ExceptionWrapper.TryCatchWhen (source line information unavailable)
 19. System.Windows.Threading.Dispatcher.WrappedInvoke (source line information unavailable)
 20. System.Windows.Threading.Dispatcher.InvokeImpl (source line information unavailable)
 21. System.Windows.Threading.Dispatcher.Invoke (source line information unavailable)
 22. MS.Win32.HwndSubclass.SubclassWndProc (source line information unavailable)
    [Internal Frame, 'M-->U']
 23. System.Windows.Threading.Dispatcher.PushFrameImpl (source line information unavailable)
 24. System.Windows.Threading.Dispatcher.PushFrame (source line information unavailable)
 25. System.Windows.Threading.Dispatcher.Run (source line information unavailable)
 26. System.Windows.Application.RunDispatcher (source line information unavailable)
 27. System.Windows.Application.RunInternal (source line information unavailable)
 28. System.Windows.Application.Run (source line information unavailable)
 29. System.Windows.Application.Run (source line information unavailable)
 30. Wmc.Gtseq.Client.Desktop.App.Main (source line information unavailable)

Второй стек потоков запускается в основном из обработчика необработанных исключений домена приложения:

*0. System.Threading.WaitHandle.WaitOne (source line information unavailable)

 1. System.Threading.WaitHandle.WaitOne (source line information unavailable)
 2. System.Windows.Threading.DispatcherOperation+DispatcherOperationEvent.WaitOne (source line information unavailable)
 3. System.Windows.Threading.DispatcherOperation.Wait (source line information unavailable)
 4. System.Windows.Threading.Dispatcher.InvokeImpl (source line information unavailable)
 5. System.Windows.Threading.Dispatcher.Invoke (source line information unavailable)
 6. Wmc.Gtseq.Core.ForwardPort.Extensions.DispatcherExtension.InvokeIfRequired (source line information unavailable)
 7. Wmc.Gtseq.Core.ForwardPort.Utilities.DispatcherHelper.InvokeOnMainThread (source line information unavailable)
 8. Wmc.Gtseq.Core.ForwardPort.Handlers.ExceptionHandler.ThreadSafeDialogHandler (source line information unavailable)
 9. Wmc.Gtseq.Core.ForwardPort.Handlers.ExceptionHandler.ShowErrorDialog (source line information unavailable)
 10. Wmc.Gtseq.Core.ForwardPort.Handlers.ExceptionHandler.HandleException (source line information unavailable)
 11. Wmc.Gtseq.Client.Desktop.App.AppDomainUnhandledException (source line information unavailable)

Похоже, что Invoke ожидает, как и ожидалось, но также кажется, что сам поток диспетчера заблокирован.Мы ждали много минут в таких ситуациях, и приложение никогда не возвращается.Любая помощь или понимание будут оценены.Я знаю, что могу переключиться на BeginInvoke, но, исходя из этого контекста, я беспокоюсь, что мой фоновый поток будет продолжен и что пользовательский интерфейс будет либо заблокирован по той же причине, либо диалоговое окно исключений не появится.

Наш фоновый потоквыполняет следующий поток кода, когда исключение обнаруживается в обработчике необработанных исключений домена:

protected override void AppDomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
    {
        ExceptionHandler.HandleException(e.ExceptionObject as Exception, false);
    }

public static void HandleException(Exception ex, bool closeApp)
    {
        ThreadSafeDialogHandler((Action)delegate { ErrorDialog.ShowDialog(ex, closeApp); });           
    }

private static void ThreadSafeDialogHandler(Action methodCall)
    {
        DispatcherHelper.InvokeOnMainThread(() => { methodCall(); });
    }

public static void InvokeOnMainThread(Action method)
    {
        Application.Current.InvokeIfRequired(method, DispatcherPriority.Normal);
    }

public static void InvokeIfRequired(this DispatcherObject control, Action methodcall, DispatcherPriority priorityForCall)
    {
        // see if we need to Invoke call to Dispatcher thread  
        if (control.Dispatcher.CheckAccess())
        {
            methodcall();
        }
        else
        {
            control.Dispatcher.Invoke(priorityForCall, methodcall);
        }
    }

1 Ответ

1 голос
/ 21 августа 2013

Вместо control.Dispatcher.Invoke попробуйте control.Dispatcher.BeginInvoke, что помогло мне раньше в таких угловых случаях.

Кроме того, ваш код кажется мне немного странным.В моем приложении я установил обработчик события AppDomain.CurrentDomain.UnhandledException в главном окне события Loaded().Событие прикрепляется к локальному методу главного окна.Поэтому мне не нужно вызывать Dispatcher, потому что событие уже вызвано в главном потоке диспетчера, даже если ошибка вообще возникает в другом потоке.

...