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);
}
}
Czy możesz opublikować swój kod? – Rachel
Napisałem kod, który uruchamia się zaczynając od obsługi nieobsługiwanego wyjątku domeny aplikacji. – Ben
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