Control.Invoke需要很长时间

问题描述

大约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:知道要寻找的内容很有帮助。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...