1

マルチユーザー マルチスレッド アプリケーション サーバーで、ある種の「インプロセスプロファイラー」コンポーネントを実装するコードを書いています。基本的には完璧に動作しています - このスレッドの CPU 使用率、SQL 待機時間などの追加情報を含むスレッドごとのスタック トレースを表示し、X 秒ごとに更新します。チェックインするところだったのですが、突然、デバッグ セッションでアプリケーションがハングしていることに気付きました。常に発生するわけではなく、ランダムに発生し、同時実行性の問題を示唆しています。詳細な調査の結果、「new StackTrace(one_of_my_threads, false)」の呼び出し中にアプリケーションがハングしたことがわかりました。デバッガーのスタックは次のとおりです。

[Managed to Native Transition]  
mscorlib.dll!System.RuntimeType.RuntimeTypeCache.MemberInfoCache<System.Reflection.RuntimeMethodInfo>.AddMethod(System.RuntimeTypeHandle declaringType = {System.RuntimeTypeHandle}, System.RuntimeMethodHandle method, System.RuntimeType.RuntimeTypeCache.CacheType cacheType) + 0x88 bytes   
mscorlib.dll!System.RuntimeType.RuntimeTypeCache.GetMethod(System.RuntimeTypeHandle declaringType, System.RuntimeMethodHandle method) + 0x2d bytes  
mscorlib.dll!System.RuntimeType.GetMethodBase(System.RuntimeTypeHandle reflectedTypeHandle, System.RuntimeMethodHandle methodHandle) + 0xf5 bytes   
mscorlib.dll!System.Diagnostics.StackFrameHelper.GetMethodBase(int i) + 0x4e bytes  
mscorlib.dll!System.Diagnostics.StackTrace.CaptureStackTrace(int iSkip, bool fNeedFileInfo = false, System.Threading.Thread targetThread, System.Exception e = null) + 0xb8 bytes   

mscorlib.dll!System.Diagnostics.StackTrace.StackTrace(System.Threading.Thread targetThread, bool needFileInfo) + 0x18 bytes 

>Almog.Next.Tools.dll!Almog.Next.Services.ThreadWorkUnit.GetStackTrace(System.Threading.Thread th = {System.Threading.Thread}, Almog.Next.Services.StackDetalization details = Simplified) Line 175 + 0x2c bytes    

Almog.Next.Tools.dll!Almog.Next.Services.ThreadWorkUnit.InternalCalculate(Almog.Next.Services.StackDetalization sdetails = Simplified) Line 131 + 0x1b bytes

Almog.Next.Tools.dll!Almog.Next.Services.ThreadWorkUnit.Calculate(Almog.Next.Services.StackDetalization sdetails = Simplified) Line 90 + 0xc bytes

Almog.Next.Tools.dll!Almog.Next.Services.InProcessProfiler.GetThreadWorks(Almog.Next.Services.StackDetalization stackLevel = Simplified) Line 41 + 0xe bytes

Almog.Next.Tools.dll!Almog.Next.CommonControls.ShowWorkloadForm.timer_Tick(object sender = {Interval = 250}, System.EventArgs e = {System.EventArgs}) Line 40 + 0x9 bytes

System.Windows.Forms.dll!System.Windows.Forms.Timer.OnTick(System.EventArgs e) + 0x17 bytes 

System.Windows.Forms.dll!System.Windows.Forms.Timer.TimerNativeWindow.WndProc(ref System.Windows.Forms.Message m) + 0x34 bytes  

System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.Callback(System.IntPtr hWnd, int msg = 275, System.IntPtr wparam, System.IntPtr lparam) + 0x5a bytes 

[Native to Managed Transition]  

[Managed to Native Transition]  

System.Windows.Forms.dll!System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(int dwComponentID, int reason = -1, int pvLoopData = 0) + 0x24e bytes 

System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(int reason = -1, System.Windows.Forms.ApplicationContext context = {System.Windows.Forms.ApplicationContext}) + 0x177 bytes 

System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoop(int reason, System.Windows.Forms.ApplicationContext context) + 0x61 bytes    

System.Windows.Forms.dll!System.Windows.Forms.Application.Run(System.Windows.Forms.Form mainForm) + 0x31 bytes  

NextServer.exe!Almog.Next.Server.Program.Main(string[] ParamStr = {string[0]}) Line 24 + 0x1d bytes

また、主に新しいオブジェクトを割り当てる (「new」を呼び出す) ときに、他のスレッドもブロックされているように見えることにも注意を払いました。次のコード行にぶら下がっているスレッドの例の 1 つ:

return new TransactionController(this, transactionMode, isolationLevel);

すべての「新しい」ものは MemberInfoCache と関係があると思いますが、Reflector を使用して AddMethod() のコードを調べた後でも何ができるかわかりません。助けてください!私は完全に立ち往生しています。

これがコード読み取りスタックトレースです。珍しいことは何もありません、私見:...

if (th == Thread.CurrentThread)
                throw new NextException("Internal error: it seems the thread {0} once called BeginWork() is the same thread which calls GetThreadWorks() now...", th.ManagedThreadId);
pragma warning disable 612, 618
            th.Suspend();
            var trace = new StackTrace(th, details == StackDetalization.Detailed);
            th.Resume();
pragma warning restore 612, 618
            var sb = new StringBuilder();
            int frameCount = trace.FrameCount;
            for (int i = 0; i < frameCount; i++)
            {                

...

前もって感謝します...

4

1 に答える 1

0

中断したスレッドがロックを保持していて、StackTrace がそのロックを使用している場合、デッドロックが発生します。

Thread.Suspend の使用は、次の理由で推奨されていません。基本的に安全に使用することはできません。BCL を含め、中断されたスレッドが実行しているコードが正確にわかっている場合にのみ使用できます。あなたはそれを知ることができません。

これに対する解決策がわかりません。スタックトレースをキャプチャするには、スレッドを一時停止する必要があると思いますか?

于 2012-04-26T10:41:54.987 に答える