Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF Application is deadlocked when invoking on the Dispatcher

We are occasionally having a situation where the application is deadlocked and it seems that the dispatcher is deadlocked with a background thread trying to invoke on the dispatcher. I don't see that either thread has any shared resources that are locked. The background thread has encountered an exception and it ends up at the app domain unhandled exception delegate because no one picked up this exception. This calls our exception handler that is tasked with insuring that our exception dialog is put onto the dispatcher.

Can someone suggest ways that I can figure out what is causing the deadlock?

The dispatcher stack follows and doesn't look out of the ordinary:

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

The second threads stack starts bascically from the app domain unhandled exception handler:

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

It appears that the Invoke is waiting as expected but also appears that the dispatcher thread itself is blocked. We have waited for many minutes in these situations and the application never comes back. Any help or insight would be appreciated. I know I can switch to BeginInvoke but based on the context here I worry that my background thread would continue and that the UI would either be blocked for the same reason or the exception dialog would not appear.

Our background thread executes the following code flow when the exception shows up at the domain unhandled exception handler:

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);
        }
    }
like image 460
Ben Avatar asked Feb 14 '12 18:02

Ben


1 Answers

Instead of control.Dispatcher.Invoke try control.Dispatcher.BeginInvoke, that has helped me before in such corner cases.

Also, your code seems a bit strange to me. In my app, I set the AppDomain.CurrentDomain.UnhandledException event handler in the main window Loaded() event. The event is attached to a local method of the main window. As such I don't need to do any Dispatcher invoking, because the event is already raised on the main dispatcher thread, even if the error does happen on another thread altogether.

like image 80
Marko Avatar answered Oct 12 '22 10:10

Marko