我正在编写代码,在我们的多用户多线程应用程序服务器中实现某种“进程内分析器”组件。它基本上是完美的 - 显示每个线程的堆栈跟踪以及一些其他信息,例如此线程的CPU利用率,SQL等待时间等,每隔X秒刷新一次。我几乎签到了,但突然我在调试会话中注意到我的应用程序被挂起了!它不是一直发生,而是randomally,暗示一些并发问题。仔细检查后,我看到该应用程序在调用“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
我还注意到其他线程看起来也被阻止,主要是在分配新对象(称为“新”)时。一个线程示例,挂在这行代码上:
return new TransactionController(this, transactionMode, isolationLevel);
我相信每一个“新”都与MemberInfoCache有关,但是即使在用Reflector查看AddMethod()的代码后也无法弄清楚我能做些什么。 请帮忙!我完全陷入困境。
这是代码读取堆栈跟踪。没什么不寻常的,imho: ...
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++)
{
...
提前致谢...
答案 0 :(得分:0)
如果你挂起的线程持有一个锁并且StackTrace正在使用该锁,那么你将会死锁。
使用Thread.Suspend 已弃用有一个原因:您基本上无法安全地使用它。如果您确切知道正在运行的挂起线程的代码,包括任何BCL内容,则只能使用它。你无法知道。
我不知道解决方案。我想线程需要暂停才能捕获堆栈跟踪?