4

バックグラウンド

お客様から、C# アプリケーションのハングが報告されました。アプリケーションがハングした時点でメモリ ダンプがあります。メモリ ダンプは、メインの UI スレッドが進行状況フォームを表示し、複数のバックグラウンド スレッドが実行されていることを示しています。バックグラウンド スレッドの 1 つが Control.Invoke をメイン スレッドに戻してフォームを更新しようとしています。CLR スタックは次のようになります。

System.Threading.WaitHandle.WaitOneNative(Microsoft.Win32.SafeHandles.SafeWaitHandle, UInt32, Boolean, Boolean) 
System.Threading.WaitHandle.WaitOne(Int64, Boolean) 
System.Threading.WaitHandle.WaitOne(Int32, Boolean) 
System.Windows.Forms.Control.WaitForWaitHandle(System.Threading.WaitHandle) 
System.Windows.Forms.Control.MarshaledInvoke(System.Windows.Forms.Control, System.Delegate, System.Object[], Boolean) 
System.Windows.Forms.Control.Invoke(System.Delegate, System.Object[]) 
profdata.com.Library.frmAsyncExec.SetMessageText(System.String) 
profdata.com.Library.frmAsyncExec.SetMessage(System.String, System.String) 
profdata.com.Library.frmAsyncExec.DoAsyncProcess(System.Object) 
System.Threading.ThreadHelper.ThreadStart_Context(System.Object) 
System.Threading.ExecutionContext.runTryCode(System.Object) 
System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode, CleanupCode, System.Object) 
System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object) 
System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object) 
System.Threading.ThreadHelper.ThreadStart(System.Object) 

UI スレッドはモーダル ループにあり、メッセージを待機しています。

System.Windows.Forms.UnsafeNativeMethods.WaitMessage() 
System.Windows.Forms.Application+ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32, Int32, Int32) 
System.Windows.Forms.Application+ThreadContext.RunMessageLoopInner(Int32, System.Windows.Forms.ApplicationContext) 
System.Windows.Forms.Application+ThreadContext.RunMessageLoop(Int32, System.Windows.Forms.ApplicationContext) 
System.Windows.Forms.Application.RunDialog(System.Windows.Forms.Form) 
System.Windows.Forms.Form.ShowDialog(System.Windows.Forms.IWin32Window) 
profdata.com.Library.frmAppletBaseForm.ShowDialog(System.Windows.Forms.IWin32Window) 
profdata.com.Library.frmAsyncExec.ExecuteProcess(System.Windows.Forms.IWin32Window) 

メッセージ キュー (私が見ることができる) 内の唯一のメッセージがペイント メッセージであることを確認しました。メッセージ 15 は WM_PAINT に対応します。

0:000> !dso
OS Thread Id: 0x126c (0)
ESP/REG  Object   Name
ebx      01a688d0 System.Windows.Forms.Application+ThreadContext
esi      01a6eb9c System.Windows.Forms.Application+ComponentManager+ComponentHashtableEntry
edi      1b0c05e0 System.Collections.Hashtable+HashtableEnumerator
0036e244 1b08430c System.Windows.Forms.NativeMethods+MSG[]

0:000> !da 1b08430c 
Name: System.Windows.Forms.NativeMethods+MSG[]
MethodTable: 67e0592c
EEClass: 67be89b8
Size: 40(0x28) bytes
Array: Rank 1, Number of elements 1, Type VALUETYPE
Element Methodtable: 67e059dc

0:000> !dumpvc 67e059dc 1b084314
Name: System.Windows.Forms.NativeMethods+MSG
MethodTable 67e059dc
EEClass: 67bbd880
Size: 36(0x24) bytes
 (C:\Windows\assembly\GAC_MSIL\System.Windows.Forms\2.0.0.0__b77a5c561934e089\System.Windows.Forms.dll)
Fields:
      MT    Field   Offset                 Type VT     Attr    Value Name
691b35f0  4002ba0        0        System.IntPtr  1 instance    b02ee hwnd
691b2f74  4002ba1        4         System.Int32  1 instance       15 message
691b35f0  4002ba2        8        System.IntPtr  1 instance        0 wParam
691b35f0  4002ba3        c        System.IntPtr  1 instance        0 lParam
691b2f74  4002ba4       10         System.Int32  1 instance 264314085 time
691b2f74  4002ba5       14         System.Int32  1 instance      188 pt_x
691b2f74  4002ba6       18         System.Int32  1 instance      386 pt_y

Control.MarshaledInvoke が既知のメッセージの PostMessage として実装されていることは知っています。

private object MarshaledInvoke(Control caller, Delegate method, object[] args, bool synchronous)
{
    ...
    System.Windows.Forms.UnsafeNativeMethods.PostMessage(new HandleRef(this, this.Handle), threadCallbackMessage, IntPtr.Zero, IntPtr.Zero);
    ...
}

MSDN はPostMessageについて次のように述べています。

指定されたウィンドウを作成したスレッドに関連付けられたメッセージ キューにメッセージを配置 (投稿) し、スレッドがメッセージを処理するのを待たずに戻ります。

これは、アプリケーションのハングを引き起こすことが知られている UI オブジェクトにアクセスするバックグラウンド スレッドの典型的なケースではないかと思います。これが悪いことであることは十分承知しています。

複数のバックグラウンド スレッドがあるため、どのバックグラウンド スレッドがめちゃくちゃになったかを特定したいと考えています。

質問

メモリ ダンプ内の情報を使用して、Control.Invoke への呼び出しの宛先スレッドを特定することは可能ですか?

これまでの作業

バックグラウンド スレッドのスタック オブジェクトのダンプを取得しました。

0:000> ~20s
0:020> !dso
OS Thread Id: 0x5d8 (20)
ESP/REG  Object   Name
ecx      01a2b2d0 System.Runtime.Remoting.Contexts.Context
0c42e49c 1b083e20 System.Threading.ManualResetEvent
0c42e524 01a2006c System.Collections.Hashtable
0c42e560 1b083e38 Microsoft.Win32.SafeHandles.SafeWaitHandle
0c42e5fc 1b044128 System.Windows.Forms.PropertyStore
0c42e608 1b060b68 System.Collections.Queue
0c42e610 1b083de0 System.Windows.Forms.Control+ThreadMethodEntry
0c42e65c 1b043b30 profdata.com.DailyReporting.frmDRAsyncExec
0c42e66c 1b083cb0 System.Object[]    (System.Object[])
0c42e670 1b083c90 profdata.com.Library.frmAsyncExec+SetMessageDelegate
0c42e674 1b083cc4 System.Windows.Forms.Control+MultithreadSafeCallScope
0c42e694 1b043b30 profdata.com.DailyReporting.frmDRAsyncExec

ThreadMethodEntry と Context オブジェクトを調べてみましたが、何を探しているのかわかりません。

0:020> !do 1b083de0 
Name: System.Windows.Forms.Control+ThreadMethodEntry
MethodTable: 67e05380
EEClass: 67be8454
Size: 52(0x34) bytes
 (C:\Windows\assembly\GAC_MSIL\System.Windows.Forms\2.0.0.0__b77a5c561934e089\System.Windows.Forms.dll)
Fields:
      MT    Field   Offset                 Type VT     Attr    Value Name
67dff750  40011b9        4 ...ows.Forms.Control  0 instance 1b043b30 caller
67dff750  40011ba        8 ...ows.Forms.Control  0 instance 1b043b30 marshaler
691b118c  40011bb        c      System.Delegate  0 instance 1b083c90 method
691844f8  40011bc       10      System.Object[]  0 instance 1b083cb0 args
691b0944  40011bd       14        System.Object  0 instance 00000000 retVal
691b0ebc  40011be       18     System.Exception  0 instance 00000000 exception
691847f4  40011bf       2c       System.Boolean  1 instance        1 synchronous
691847f4  40011c0       2d       System.Boolean  1 instance        0 isCompleted
69197b54  40011c1       1c ....ManualResetEvent  0 instance 1b083e20 resetEvent
691b0944  40011c2       20        System.Object  0 instance 1b083e14 invokeSyncObject
691ada1c  40011c3       24 ....ExecutionContext  0 instance 1b083cd0 executionContext
691aa00c  40011c4       28 ...ronizationContext  0 instance 00000000 syncContext

0:020> !do 01a2b2d0 
Name: System.Runtime.Remoting.Contexts.Context
MethodTable: 691a210c
EEClass: 68fcf620
Size: 60(0x3c) bytes
 (C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
Fields:
      MT    Field   Offset                 Type VT     Attr    Value Name
691844f8  4001f60        4      System.Object[]  0 instance 01a2b3a0 _ctxProps
691a219c  4001f61        8 ...micPropertyHolder  0 instance 00000000 _dphCtx
691a75b4  4001f62        c ...em.LocalDataStore  0 instance 00000000 _localDataStore
69196f18  4001f63       10 ...ging.IMessageSink  0 instance 00000000 _serverContextChain
69196f18  4001f64       14 ...ging.IMessageSink  0 instance 00000000 _clientContextChain
691b1508  4001f65       18     System.AppDomain  0 instance 01a01298 _appDomain
691844f8  4001f66       1c      System.Object[]  0 instance 00000000 _ctxStatics
691b35f0  4001f67       20        System.IntPtr  1 instance   551520 _internalContext
691b2f74  4001f68       24         System.Int32  1 instance        0 _ctxID
691b2f74  4001f69       28         System.Int32  1 instance        3 _ctxFlags
691b2f74  4001f6a       2c         System.Int32  1 instance        1 _numCtxProps
691b2f74  4001f6b       30         System.Int32  1 instance        0 _ctxStaticsCurrentBucket
691b2f74  4001f6c       34         System.Int32  1 instance        0 _ctxStaticsFreeIndex
691a219c  4001f6d      654 ...micPropertyHolder  0   shared   static _dphGlobal
    >> Domain:Value  00557ff8:01a2b068 <<
69189944  4001f6e      658 ...LocalDataStoreMgr  0   shared   static _localDataStoreMgr
    >> Domain:Value  00557ff8:01a2b07c <<
691b2f74  4001f6f      b40         System.Int32  1   shared   static _ctxIDCounter
    >> Domain:Value  00557ff8:0 <<

または、特定のスレッドへのウィンドウハンドルの関連付けを見つけることを含む、よりネイティブなアプローチがあるかもしれませんが、そうであれば、その方法がわかりません。

4

1 に答える 1

1

UIスレッドで実行されるデリゲート(メソッドフィールド)をThreadMethodEntryにダンプする必要があります。他のメンバーはそこにのみ存在するため、UIスレッドは、コールバックを送信するコントロールと、コールバックが実行される同期コンテキストを認識します。

また、呼び出しが必要かどうかを確認するためのフラグと、呼び出しが失敗した場合の例外フィールドがあります。これは、呼び出し呼び出しを介して行われた場合は、呼び出し元にマーシャリングして戻すことができます。そこにある他のものは無視しても問題ありません。

デリゲートインスタンスのみが手元にある場合にどのメソッドが呼び出されたかを確認する方法の詳細については、http://geekswithblogs.net/akraus1/archive/2012/05/20/149699.aspxを参照してください。

コールバックも実行されないため、他のスレッドも確認する必要があります。このような不思議なハングは、UI以外のスレッドがコントロールを呼び出そうとするWM_SETTING_CHANGEウィンドウメッセージと関連して発生することがよくあります(http://ikriv.com/dev/dotnet/MysteriousHang.html#BeginInvokeDanceを参照)。

于 2013-01-24T22:22:17.550 に答える