我们有一个WPF繁忙窗口指示器。它在主线上使用window.ShowDialog()
显示。响应Loaded事件时,将执行一个操作,并关闭该窗口,以便应用程序继续其工作。ShowDialog方法挂起而不显示窗口Dead死锁?
window.ShowDialog()
似乎不时地(很少)挂起而没有显示对话框,并且Loaded事件未被触发,因此应用程序挂起。相关的代码是下列之一:
private void BusyIndicatorAsyncCall(string text, Action<DoWorkEventArgs> doWorkDinamicView = null, Action doWork = null, Action workCompleted = null, Action<Exception> exceptionReturn = null)
{
Window window = this.CreateWindowOfBusyIndicator(text);
Dispatcher dispatcher = window.Dispatcher;
BackgroundWorker backgoundworker = new BackgroundWorker();
IViewModel viewModel = (window.Content as UserControl).DataContext as IViewModel;
this.Modals.Add(viewModel, window);
if (doWorkDinamicView != null)
{
DoWorkEventArgs eventArgs = new DoWorkEventArgs(window.Content);
backgoundworker.DoWork += (s, e) => doWorkDinamicView.Invoke(eventArgs);
}
else if (doWork != null)
{
backgoundworker.DoWork += (s, e) => { doWork.Invoke(); };
}
backgoundworker.RunWorkerCompleted += (s, e) =>
{
Exception exception = e.Error;
if (exception == null)
{
if (workCompleted != null)
{
try
{
this.StyleName = null;
workCompleted.Invoke();
}
catch (Exception ex)
{
exception = ex;
}
}
}
this.Modals.Remove(viewModel);
dispatcher.Invoke(new Action(window.Close));
if (exception != null)
{
if (exceptionReturn == null)
throw new Exception("Error en RunWorkerCompleted.", exception);
else
exceptionReturn(exception);
}
};
RoutedEventHandler onLoaded = new RoutedEventHandler((sender, e) =>
{
try
{
backgoundworker.RunWorkerAsync();
}
catch
{
}
});
this.BusyIndicatorImpl(window, onLoaded);
}
private void BusyIndicatorImpl(Window window, RoutedEventHandler onLoaded)
{
window.Loaded += onLoaded;
window.ShowDialog();
window.Loaded -= onLoaded;
}
当应用程序挂起,我可以看到在window.ShowDialog()
方法的指令指针,但窗口不可见的应用和BackgroundWorker的尚未开始,所以我的猜测是OnLoaded事件尚未提出。
该应用程序并未真正挂起,因为它正确重画,但无法单击屏幕上的任何位置。作为一个边奇怪的效果,当应用程序挂起它从任务栏自败在Windows 7
调用堆栈我看时,我打破了执行是下面的一个:
[email protected]() + 0x15 bytes
[email protected]() + 0x15 bytes
[Managed to Native Transition]
WindowsBase.dll!MS.Win32.UnsafeNativeMethods.GetMessageW(ref System.Windows.Interop.MSG msg, System.Runtime.InteropServices.HandleRef hWnd, int uMsgFilterMin, int uMsgFilterMax) + 0x14 bytes
WindowsBase.dll!System.Windows.Threading.Dispatcher.GetMessage(ref System.Windows.Interop.MSG msg, System.IntPtr hwnd, int minMessage, int maxMessage) + 0x80 bytes
WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrameImpl(System.Windows.Threading.DispatcherFrame frame) + 0x75 bytes WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrame(System.Windows.Threading.DispatcherFrame frame) + 0x49 bytes
PresentationFramework.dll!System.Windows.Window.ShowHelper(object booleanBox) + 0x17d bytes
PresentationFramework.dll!System.Windows.Window.Show() + 0x5c bytes
PresentationFramework.dll!System.Windows.Window.ShowDialog() + 0x27d bytes
> xxx.dll!xxx.BusyIndicatorImpl(System.Windows.Window window, System.Windows.RoutedEventHandler onLoaded) Line 743 + 0xd bytes C#
正如有人说,它看起来前像一个僵局,所以我得到了与Visual Studio转储并运行一些工具,寻找死锁。这是在应用程序运行的线程的信息:
Debugger Thread ID Managed Thread ID OS Thread ID Thread Object GC Mode Domain Lock Count Apt Exception
0 1 5684 2b2390 Preemptive 9176600 0 STA
6 2 5572 2c7a80 Preemptive 2a82f8 0 MTA (Finalizer)
7 3 3676 2cb828 Preemptive 2a82f8 0 Unknown
11 4 864 7f7d5c0 Preemptive 2a82f8 0 MTA (Threadpool Worker)
15 10 4340 921cdc8 Preemptive 9176600 1 MTA
16 12 1648 9438560 Preemptive 2a82f8 0 MTA (Threadpool Completion Port)
17 14 3380 9001038 Preemptive 2a82f8 0 Unknown (Threadpool Worker)
21 7 5336 9002fe8 Preemptive 2a82f8 0 MTA (Threadpool Worker)
20 5 4120 9003fc0 Preemptive 2a82f8 0 MTA (Threadpool Worker)
25 18 5172 9004508 Preemptive 2a82f8 0 MTA (Threadpool Worker)
27 11 5772 9003a78 Preemptive 2a82f8 0 MTA (Threadpool Worker)
只有一个线程与应用程序代码(0,1管理与ShowDialog的调用)。其他线程没有应用程序代码,线程15(托管10)是唯一带有一些.Net代码的线程。
放眼线15(管理10),因为它是一个带有锁我看到下面的调用堆栈:
[[HelperMethodFrame_1OBJ] (System.Threading.WaitHandle.WaitMultiple)] System.Threading.WaitHandle.WaitMultiple(System.Threading.WaitHandle[], Int32, Boolean, Boolean)
mscorlib_ni!System.Threading.WaitHandle.WaitAny(System.Threading.WaitHandle[], Int32, Boolean)+92
System_ni!System.Net.TimerThread.ThreadProc()+28f
mscorlib_ni!System.Threading.ThreadHelper.ThreadStart_Context(System.Object)+6f
mscorlib_ni!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)+a7
mscorlib_ni!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)+16
mscorlib_ni!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)+41
mscorlib_ni!System.Threading.ThreadHelper.ThreadStart()+44
[[GCFrame]]
[[DebuggerU2MCatchHandlerFrame]]
[[ContextTransitionFrame]]
[[DebuggerU2MCatchHandlerFrame]]
此调用堆栈看起来像一个计时器等待被解雇我,但也许我这个解释错了,所以我不知道如何继续这个。
我可以根据要求提供您需要的任何信息。我不是WinDbg的专家,但我开始能够处理它,所以你可以让我也获得它的信息。
UPDATE:
增加了一些日志,我们有如下的额外信息的应用程序后:
的问题是,该方法dispatcher.Invoke(new Action(window.Close));
被调用,它执行没有抛出异常,但该方法window.ShowDialog();
不返回。
我们试图用Spy ++和类似的工具找到窗口,并且据我所知,该窗口不存在,但window.ShowDialog();
仍在执行。
我希望这能让你对发生的事情有所了解。
任何你在玩里面装载的线程/异步方法chanse? – 3615
多个'Dispatcher' /线程?窗口函数的钩子?其他“低级”东西(P/Invoke)? – dymanoid
你还在做什么在加载处理程序?你有没有在那里放置一个断点,看它是否被击中? – Clemens