2012-02-14 10 views
13

Occasionalmente ci sono situazioni in cui l'applicazione è bloccata in un deadlock e sembra che il dispatcher sia bloccato in un deadlock con un thread in background che tenta di richiamare il dispatcher. Non vedo che entrambi i thread abbiano risorse condivise che sono bloccate. Il thread in background ha riscontrato un'eccezione e finisce nel delegato di eccezione non gestito del dominio dell'app perché nessuno ha rilevato questa eccezione. Questo chiama il nostro gestore di eccezioni che ha il compito di assicurare che la nostra finestra di dialogo delle eccezioni sia posta sul dispatcher.L'applicazione WPF è bloccata in caso di richiamo sul Dispatcher

Qualcuno può suggerire dei modi per capire che cosa sta causando il deadlock?

Lo stack dispatcher segue e non sembra fuori dal comune:

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

Il secondo discussioni impilano inizia bascically dal dominio applicazione gestore di eccezione non gestita:

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

Sembra che il Invoke è in attesa come previsto ma appare anche che il thread del dispatcher stesso è bloccato. Abbiamo aspettato molti minuti in queste situazioni e l'applicazione non ritorna mai. Qualsiasi aiuto o intuizione sarebbe apprezzato. So che posso passare a BeginInvoke ma in base al contesto qui mi preoccupo che il mio thread in background continui e che l'interfaccia utente sia bloccata per lo stesso motivo o la finestra di dialogo delle eccezioni non venga visualizzata.

nostro thread in background viene eseguito il seguente flusso di codice quando l'eccezione si presenta al gestore di eccezione non gestita di dominio:

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

Puoi pubblicare il tuo codice? – Rachel

+0

Ho pubblicato il codice che viene eseguito a partire dal gestore delle eccezioni non gestito del dominio dell'app. – Ben

+0

Sarebbe più interessante vedere la traccia dello stack del thread dell'interfaccia utente mentre il deadlock è attivo. Il thread dell'interfaccia utente probabilmente sta aspettando qualcosa in modo che il dispatcher venga bloccato. Interrompere il debugger la volta successiva che si verifica il deadlock e controllare la traccia dello stack del thread dell'interfaccia utente. Potrebbe essere che il thread dell'interfaccia utente si trovi in ​​un Thread.Join (o qualcosa di simile) mentre il thread in background tenta di eseguire Invoke sul dispatcher? Ho smesso di usare Invoke molto tempo fa a causa di deadlock .. solo BeginInvoke. – stmax

risposta

1

Invece di provare control.Dispatcher.Invokecontrol.Dispatcher.BeginInvoke, che mi ha aiutato prima in questi casi d'angolo.

Inoltre, il tuo codice mi sembra un po 'strano. Nella mia app, ho impostato il gestore di eventi AppDomain.CurrentDomain.UnhandledException nella finestra principale Loaded() evento. L'evento è collegato a un metodo locale della finestra principale. Pertanto, non è necessario eseguire alcun richiamo di Dispatcher, poiché l'evento è già stato generato nel thread del dispatcher principale, anche se l'errore si verifica su un altro thread.

+0

Non è sempre possibile passare da 'Invoke' a' BeginInvoke'. Il primo è sincrono e il secondo è asincrono. Se il destinatario dipende dagli effetti della chiamata invocata, potrebbe essere così facile. –

Problemi correlati