2012-02-14 10 views
13

Czasami mamy sytuację, w której aplikacja jest zakleszczona i wygląda na to, że dyspozytor jest zakleszczony z wątkiem tła, który próbuje wywołać na dyspozytorze. Nie widzę, aby żaden wątek miał zablokowane zasoby wspólne. Wątek w tle napotkał wyjątek i kończy się na nieobsłużonym wyjątku delegowania wyjątków w domenie aplikacji, ponieważ nikt nie wybrał tego wyjątku. To wywołuje nasz program obsługi wyjątków, który ma za zadanie zapewnić, że nasze okno dialogowe wyjątku zostanie umieszczone w module rozsyłającym.Aplikacja WPF jest zakleszczona podczas wywoływania na Dispatcherze

Czy ktoś może zasugerować sposób, aby dowiedzieć się, co powoduje impas?

Dyspozytor stos następuje i nie wygląda niezwykłego:

*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) 

Drugi wątki stos zaczyna bascically z App domeny obsługi nieobsługiwany wyjątek:

*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) 

Wydaje się, że Wywołanie oczekuje zgodnie z oczekiwaniami, ale wydaje się również, że sam wątek dyspozytora jest zablokowany. Czekaliśmy wiele minut w takich sytuacjach, a aplikacja nigdy nie wraca. Każda pomoc lub wgląd byłyby docenione. Wiem, że mogę przejść do BeginInvoke, ale w oparciu o kontekst tutaj martwię się, że wątek w tle będzie kontynuowany i że interfejs będzie albo zablokowany z tego samego powodu, albo okno dialogowe wyjątku nie pojawi się.

Nasz wątek tła wykonuje następujące przepływ kodu gdy wyjątek pojawia się na nieobsługiwany obsługi wyjątków domeny:

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); 
     } 
    } 
+0

Czy możesz opublikować swój kod? – Rachel

+0

Napisałem kod, który uruchamia się zaczynając od obsługi nieobsługiwanego wyjątku domeny aplikacji. – Ben

+0

Byłoby bardziej interesujące zobaczyć ślad stosu wątku interfejsu użytkownika, gdy zakleszczenie jest aktywne. Wątek interfejsu prawdopodobnie czeka na coś, więc dyspozytor zostanie zablokowany. Przerwij debuger następnym razem, gdy wystąpi zakleszczenie i sprawdź ślad stosu w wątku interfejsu użytkownika. Czy to możliwe, że twój wątek interfejsu użytkownika znajduje się w Thread.Join (lub czymś podobnym), podczas gdy twój wątek w tle próbuje wywołać komendę? Przestałem używać Invoke dawno temu z powodu zakleszczeń .. tylko BeginInvoke. – stmax

Odpowiedz

1

Zamiast control.Dispatcher.Invoke spróbować control.Dispatcher.BeginInvoke, że pomógł mi wcześniej w takich przypadkach narożnych.

Twój kod wydaje się też nieco dziwny. W mojej aplikacji ustawiam obsługę zdarzeń AppDomain.CurrentDomain.UnhandledException w zdarzeniu głównym okna Loaded(). Zdarzenie jest dołączone do lokalnej metody głównego okna. W związku z tym nie muszę wykonywać żadnych wywołań Dispatchera, ponieważ zdarzenie jest już wywoływane w głównym wątku kontrolera, nawet jeśli błąd występuje całkowicie w innym wątku.

+0

Nie zawsze można przestawić się z 'Invoke' na' BeginInvoke'. Ten pierwszy jest synchroniczny, a drugi jest asynchroniczny. Jeśli osoba odwołująca się zależy od efektów wywołanego połączenia, może to być łatwe. –

Powiązane problemy