问题描述
大约15个月的WinForms应用程序出现了问题,该应用程序正在积极维护中。大约有十家公司正在使用它,每家公司都在大约5至20个客户上运行它。其中,我们使用商业打印机驱动程序(PDF X-Change)从打印输出中创建PDF,该文件采用异步回调机制来通知应用程序已创建(或未创建)PDF。应用程序使用此信息在窗口中显示PDF文件。基本上是这样的:
void pdfCreationStatusCallback(PdfCreationStatusArgs pcsa)
{
if (InvokeRequired)
{
Invoke(new PdfCreationStatus(pdfCreationStatusCallback),pcsa);
return;
}
displayPdf(pcsa);
}
一家新公司开始使用该软件,并报告该应用程序有时会挂起。调试后,我注意到调用Invoke()
有时需要20秒到几乎两个小时才能返回!我将远程调试与.NET Framework调试(使用dotPeek)结合使用,以了解实际情况。我能够一直追踪到WaitHandle.cs中的以下代码:
[SecurityCritical]
internal static bool InternalWaitOne(
SafeHandle waitableSafeHandle,long millisecondsTimeout,bool hasThreadAffinity,bool exitContext)
{
if (waitableSafeHandle == null)
throw new ObjectDisposedException((string) null,Environment.GetResourceString("ObjectDisposed_Generic"));
int num = WaitHandle.WaitOneNative(waitableSafeHandle,(uint) millisecondsTimeout,hasThreadAffinity,exitContext);
if (AppDomainPauseManager.IsPaused)
AppDomainPauseManager.ResumeEvent.WaitOneWithoutFAS();
if (num == 128)
WaitHandle.ThrowAbandonedMutexException();
return num != 258;
}
在这里,我注意到在“健康”的系统上,对WaitHandle.WaitOneNative(...)
的调用返回0,因此该方法返回true,并且一切都很好。在受影响的系统上,WaitHandle.WaitOneNative(...)
返回258(1000毫秒后,这是millisecondsTimeout的值),因此该方法返回false。然后,调用InternalWaitOne(..)
的方法将在循环中对其进行调用,直到WaitHandle.WaitOneNative(...)
最终返回一个非258的值(如上所述,它甚至可能需要两个小时)。我的问题是,只有以下声明,我找不到WaitOneNative(..)
的源代码:
[SecurityCritical]
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern int WaitOneNative(
SafeHandle waitableSafeHandle,uint millisecondsTimeout,bool exitContext);
当我在int num = WaitHandle.WaitOneNative(..)
行设置断点时,我有两个线程都到达那个位置,都返回num = 258:
这是创建PDF的回调函数(_pdfPrinter_OnFileSaved
)的堆栈跟踪:
> mscorlib.dll!System.Threading.WaitHandle.InternalWaitOne(System.Runtime.InteropServices.SafeHandle waitableSafeHandle,bool exitContext) Line 193 C#
mscorlib.dll!System.Threading.WaitHandle.WaitOne(int millisecondsTimeout,bool exitContext) Line 125 C#
System.Windows.Forms.dll!System.Windows.Forms.Control.WaitForWaitHandle(System.Threading.WaitHandle waitHandle) Line 2788 C#
System.Windows.Forms.dll!System.Windows.Forms.Control.MarshaledInvoke(System.Windows.Forms.Control caller,System.Delegate method,object[] args,bool synchronous) Line 4825 C#
System.Windows.Forms.dll!System.Windows.Forms.Control.Invoke(System.Delegate method,object[] args) Line 4551 C#
GUISubsystem.dll!GUISubsystem.CalculationForms.Printouts.PrintoutAnbotsartikel.FrmAnbotsartikelDruckParameter.pdfCreationStatusCallback(PdfCreationStatusArgs pcsa) Line 597 C#
PrinterSubsystem.dll!PrinterSubsystem.PrintingManager._pdfPrinter_OnFileSaved(int jobID,string fileName) Line 885 C#
[Übergang von Nativ zu Verwaltet]
[Übergang von Verwaltet zu Nativ]
mscorlib.dll!System.Delegate.DynamicInvokeImpl(object[] args) Line 113 C#
mscorlib.dll!System.Runtime.InteropServices.ComEventsMethod.DelegateWrapper.Invoke(object[] args) Line 158 C#
mscorlib.dll!System.Runtime.InteropServices.ComEventsMethod.Invoke(object[] args) Line 121 C#
mscorlib.dll!System.Runtime.InteropServices.ComEventsSink.System.Runtime.InteropServices.NativeMethods.IDispatch.Invoke(int dispid,ref System.Guid riid,int lcid,System.Runtime.InteropServices.ComTypes.INVOKEKIND wFlags,ref System.Runtime.InteropServices.ComTypes.DISPPARAMS pDispParams,System.IntPtr pvarResult,System.IntPtr pExcepInfo,System.IntPtr puArgErr) Line 153 C#
这是另一个线程的堆栈跟踪(看起来像主消息循环):
> mscorlib.dll!System.Threading.WaitHandle.InternalWaitOne(System.Runtime.InteropServices.SafeHandle waitableSafeHandle,bool exitContext) Line 125 C#
System.Windows.Forms.dll!System.Windows.Forms.Control.WaitForWaitHandle(System.Threading.WaitHandle waitHandle) Line 2793 C#
System.Windows.Forms.dll!System.Windows.Forms.Control.MarshaledInvoke(System.Windows.Forms.Control caller,object[] args) Line 4551 C#
System.Windows.Forms.dll!System.Windows.Forms.WindowsFormsSynchronizationContext.Send(System.Threading.SendOrPostCallback d,object state) Line 74 C#
System.dll!Microsoft.Win32.SystemEvents.SystemEventInvokeInfo.Invoke(bool checkFinalization,object[] args) Line 1272 C#
System.dll!Microsoft.Win32.SystemEvents.RaiseEvent(bool checkFinalization,object key,object[] args) Line 970 C#
System.dll!Microsoft.Win32.SystemEvents.OnUserPreferenceChanged(int msg,System.IntPtr wParam,System.IntPtr lParam) Line 728 C#
System.dll!Microsoft.Win32.SystemEvents.WindowProc(System.IntPtr hWnd,int msg,System.IntPtr lParam) Line 1130 C#
[Übergang von Nativ zu Verwaltet]
[Übergang von Verwaltet zu Nativ]
System.Windows.Forms.dll!System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(System.IntPtr dwComponentID,int reason,int pvLoopData) Line 1258 C#
System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(int reason,System.Windows.Forms.ApplicationContext context) Line 2042 C#
System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoop(int reason,System.Windows.Forms.ApplicationContext context) Line 1982 C#
System.Windows.Forms.dll!System.Windows.Forms.Application.Run(System.Windows.Forms.Form mainForm) Line 988 C#
MainEntry.exe!MainEntry.Main(string[] args) Line 118 C#
另一个观察结果:第一次调用Invoke()
(因此WaitOneNative()
)只花费这么长时间。 WaitOneNative()
返回0(而不是258)后,应用程序将立即运行。重新启动应用程序后,将对其进行“重置”。这是第一个也是第一个在3/7客户上遇到此问题的公司。其中一个客户端使用Windows 10,另两个客户端使用.Net Framework 4.8。我们的应用程序针对.Net Framework 4.5。
有人可以告诉我在哪里可以找到static extern int WaitOneNative(..)
的源代码,以便我可以进一步调查它在等待什么吗?
和/或没有人暗示这里可能发生什么。 WaitOnNative()
在几秒钟到几小时之间可能要等待什么?我应该在堆栈跟踪,线程等中寻找什么?
解决方法
我能够确定问题所在。这是上述@klaus-gütter中的julia> f(x,y) = @generated() ? :x : y
f (generic function with 1 method)
julia> _invoke(f,1,2; generated=true)
1
julia> _invoke(f,2; generated=false)
2
个问题之一。我们有一个Windows.Forms.Form被创建为后台线程之一。 OnUserPreferenceChanged
回调只是由于“错误”而挂起的回调之一(它本身并不是罪魁祸首),可能是因为它是在前面提到的后台线程之后第一个被调用的回调。我使用这里描述的方法调试了它:link(...这个主题上有很多无效链接)。
我不真正理解的是为什么它最终会被执行(1-2小时后),以及为什么使用该软件只影响70台左右的计算机中的3-4台,但我可以接受
非常感谢对原始帖子发表评论的每个人,尤其是@klaus-gütter和@Jimi:知道要寻找的内容很有帮助。