您的位置:首页 > 其它

.NET常见线程简介

2009-01-30 10:41 218 查看
原文地址:http://blogs.msdn.com/tess/archive/2005/12/20/505862.aspx

当你分析一个dump文件的时候,调试里面最艺术的地方就是知道哪些东西是可以忽略的,而哪些是你想要的东西。

特别是在你分析一个程序停止响应(hang)的bug时,了解这些常见线程对你非常有帮助,浏览线程各堆栈列表的时候,你可以知道不是这个线程出问题了,也不是那个线程…………

因为大部分时间我是跟asp.net打交道,所以我将通过分析w3wp.exe(IIS6里面用来执行asp.net页面代码的进程)的一个dump文件来介绍这些常见线程。所有这些常见线程都有一个共性,就是它们要么是睡眠状态(sleepingstate)或者等待状态(waitingstate),等待处理更多的工作。因此虽然它们看起来是造成程序停止响应(hang)的原因,实际上它们并不是真正的罪魁祸首……如果你发现它们处于其他的状态,比如说正在执行某个任务,那么它们就需要得到更多的关注了。

我把这些常见的线程划分为以下几个种类:
1.CLR线程
2.W3WP线程
3.RPC线程
4.其他COM线程

CLR线程
线程池(ThreadPool)管理程序有五种主要的线程类型:

1.CompletionPort/IO线程和工作(Worker)线程是执行你的托管(managed)代码和.net代码的线程。
2.一个闸门(gate)线程根据CPU的利用率,GC的频率和工作队列(workerqueue)的大小,动态地创建或销毁工作线程和IO线程。
3.停滞(wait)线程,用来等待一些同步对象触发的事件,比如说,一个程序员使用WaitHandle类(或它的派生类),这个类内部使用WaitForSingleObjectWin32API函数来是这个线程处于停滞状态。
4.最后第五个是定时器(Timer)线程,它是用来调用定时器(Timer)回调函数的线程。

下面的列表列出了.NET1.1中它们在停滞状态时候的模样(由于我在翻译的时候,机器上没有微软.NET2.0的公开符号文件,所以只好原文拷贝下来了,有机会我会将2.0里面的堆栈列出来):

闲置状态中的CLR工作线程(WorkerThread):
11Id:fb8.268Suspend:0Teb:7ffaa000Unfrozen

ChildEBPRetAddrArgstoChild

0199fdf87c82212477e6baa80000023400000000ntdll!KiFastSystemCallRet

0199fdfc77e6baa800000234000000000199fe40ntdll!NtWaitForSingleObject+0xc

0199fe6c77e6ba120000023400009c4000000000kernel32!WaitForSingleObjectEx+0xac

0199fe80791d401f0000023400009c4000000000kernel32!WaitForSingleObject+0x12

0199fea4791fdacc000000000000000080a56bccmscorsvr!ThreadpoolMgr::WorkerThreadStart+0x3a

0199ffb877e66063000b6da80000000000000000mscorsvr!ThreadpoolMgr::intermediateThreadProc+0x44

0199ffec00000000791fda8b000b6da800000000kernel32!BaseThreadStart+0x34

闲置状态中的CLRCompletionPort/IOThread:
9Id:fb8.ef8Suspend:0Teb:7ffac000Unfrozen

ChildEBPRetAddrArgstoChild

0191fec07c821bf477e6611a0000023c0191ff1cntdll!KiFastSystemCallRet

0191fec477e6611a0000023c0191ff1c0191ff08ntdll!NtRemoveIoCompletion+0xc

0191fef0791fdb220000023c0191ff180191ff1ckernel32!GetQueuedCompletionStatus+0x29

0191ff24791fdacc00000001809a05fe7ffac000mscorsvr!ThreadpoolMgr::CompletionPortThreadStart+0x49

0191ffb877e66063000b6da80000000000000000mscorsvr!ThreadpoolMgr::intermediateThreadProc+0x44

0191ffec00000000791fda8b000b6da800000000kernel32!BaseThreadStart+0x34


闲置状态中的CLR闸门(gate)线程:
10Id:fb8.bdcSuspend:0Teb:7ffab000Unfrozen

ChildEBPRetAddrArgstoChild

0195fe507c82136477e42439000000000195fe94ntdll!KiFastSystemCallRet

0195fe5477e42439000000000195fe9400000000ntdll!NtDelayExecution+0xc

0195febc77e424b7000001f4000000000195ffb8kernel32!SleepEx+0x68

0195fecc791bf4f9000001f40b2646e600000939kernel32!Sleep+0xf

0195ffb877e66063000000000000000000000000mscorsvr!ThreadpoolMgr::GateThreadStart+0x54

0195ffec00000000791bf4a50000000000000000kernel32!BaseThreadStart+0x34

闲置状态中的CLR停滞(wait)线程:
25Id:230.ac0Suspend:0Teb:7ff4c000Unfrozen

ChildEBPRetAddrArgstoChild

1b88ff6c7c573a4e000000011b88ff8400000000NTDLL!ZwDelayExecution+0xb

1b88ff8c7923558cffffffff00000001198ba828KERNEL32!SleepEx+0x32

1b88ffb47c57438b00000000198ba828197f7498mscorsvr!ThreadpoolMgr::WaitThreadStart+0x45

1b88ffec000000007923556a1973b3d000000000KERNEL32!BaseThreadStart+0x52

闲置状态中的CLR定时器(Timer)线程:
18Id:fb8.914Suspend:0Teb:7ff5f000Unfrozen

ChildEBPRetAddrArgstoChild

0224ff387c82136477e42439000000010224ff7cntdll!KiFastSystemCallRet

0224ff3c77e42439000000010224ff7c000003e8ntdll!NtDelayExecution+0xc

0224ffa4791cc578000003e80000000100000000kernel32!SleepEx+0x68

0224ffb877e66063000000000000000000000000mscorsvr!ThreadpoolMgr::TimerThreadStart+0x30

0224ffec00000000791cc5480000000000000000kernel32!BaseThreadStart+0x34

除了这些线程,CLR还创建了一些其他的线程:

在一个多核主机上,在一个CLR宿主进程中(服务器版本的GC),每一个处理器都会由一个垃圾回收(GC)线程,而在超线程系统上,每个进程会有两个。这些线程用来处理托管堆上的垃圾回收操作。

另外在每一个进程里我们还有终结器线程(FinalizerThread),这个线程运行所有的Finalize函数。在调试进程无响应(hang)和高内存使用率的情形时,要特别注意这个线程。如果在收集一个对象(finalizinganobject)的时候它被其他的东西阻塞(blockedinanyway)的话,那么你的托管变量就不能被以合适的方式清理掉,最终你就得到一个内存泄漏的结果,并且/或者有一个高CPU使用率的情形,因为GC将不得不重复启动以保证你的内存可用率。

最后,CLR还提供了一个DebuggerThread用来提供托管程序调试服务。

闲置状态中的CLR垃圾回收(GC)线程:
13Id:fb8.c10Suspend:0Teb:7ffa8000Unfrozen

ChildEBPRetAddrArgstoChild

01d6fefc7c82212477e6baa8000002b400000000ntdll!KiFastSystemCallRet

01d6ff0077e6baa8000002b40000000000000000ntdll!NtWaitForSingleObject+0xc

01d6ff7077e6ba12000002b4ffffffff00000000kernel32!WaitForSingleObjectEx+0xac

01d6ff84791fe6b0000002b4ffffffff00000000kernel32!WaitForSingleObject+0x12

01d6ffac792356be0000000001d6ffec77e66063mscorsvr!gc_heap::gc_thread_function+0x2f

01d6ffb877e66063000d2ed80000000000000000mscorsvr!gc_heap::gc_thread_stub+0x1e

01d6ffec00000000792356a0000d2ed800000000kernel32!BaseThreadStart+0x34

闲置状态中的CLR终结器(Finalizer)线程:
17Id:fb8.7b0Suspend:0Teb:7ffa4000Unfrozen

ChildEBPRetAddrArgstoChild

01e6fdf87c82211477e6711b0000000201e6fe48ntdll!KiFastSystemCallRet

01e6fdfc77e6711b0000000201e6fe4800000001ntdll!NtWaitForMultipleObjects+0xc

01e6fea477e6107500000002793eee0800000000kernel32!WaitForMultipleObjectsEx+0x11a

01e6fec07927826b00000002793eee0800000000kernel32!WaitForMultipleObjects+0x18

01e6fee0791fecf4000002dc00000000792376a4mscorsvr!WaitForFinalizerEvent+0x5a

01e6ff247924568100000000809a05fe7ffa4000mscorsvr!GCHeap::FinalizerThreadStart+0x96

01e6ffb877e66063000d55000000000000000000mscorsvr!Thread::intermediateThreadProc+0x44

01e6ffec0000000079245640000d550000000000kernel32!BaseThreadStart+0x34

闲置状态中的CLR调试(Debugger)线程:
12Id:fb8.b30Suspend:0Teb:7ffa9000Unfrozen

ChildEBPRetAddrArgstoChild

01adfe707c82211477e6711b0000000301adfec0ntdll!KiFastSystemCallRet

01adfe7477e6711b0000000301adfec000000001ntdll!NtWaitForMultipleObjects+0xc

01adff1c77e610750000000301adff5c00000000kernel32!WaitForMultipleObjectsEx+0x11a

01adff3879238fd60000000301adff5c00000000kernel32!WaitForMultipleObjects+0x18

01adffa079238f4d000000000000000000000000mscorsvr!DebuggerRCThread::MainLoop+0x90

01adffb07923a71401adffec77e66063019d1eb0mscorsvr!DebuggerRCThread::ThreadProc+0x68

01adffb877e66063019d1eb00000000000000000mscorsvr!DebuggerRCThread::ThreadProcStatic+0xb

01adffec000000007923a709019d1eb000000000kernel32!BaseThreadStart+0x34

W3WP线程
W3WP进程里面主要有主线程、线程池线程和压缩线程。

主线程负责启动和关闭进程,线程池线程用来处理页面请求,而压缩线程就如名字如表明的那样是用来处理压缩数据的。

W3WP主(main)线程:
.0Id:fb8.fd8Suspend:0Teb:7ffdf000Unfrozen

ChildEBPRetAddrArgstoChild

0006fc087c82212477e6baa80000018400000000ntdll!KiFastSystemCallRet

0006fc0c77e6baa8000001840000000000000000ntdll!NtWaitForSingleObject+0xc

0006fc7c77e6ba1200000184ffffffff00000000kernel32!WaitForSingleObjectEx+0xac

0006fc905a36467a00000184ffffffff00000000kernel32!WaitForSingleObject+0x12

0006fca05a366e6300254ff85a3af41d00000000w3dt!WP_CONTEXT::RunMainThreadLoop+0x10

0006fca85a3af41d0000000064711da900000000w3dt!UlAtqStartListen+0x2d

0006fcb85a3bc2590100141c010013e4010012d0w3core!W3_SERVER::StartListen+0xbd

0006ff0c0100187c00000007002538e000000000w3core!UlW3Start+0x26e

0006ff4401001a2300000007002538e0002543d0w3wp!wmain+0x22a

0006ffc077e523cd00000000000000007ffd7000w3wp!wmainCRTStartup+0x12b

0006fff000000000010018f80000000078746341kernel32!BaseProcessStart+0x23

闲置状态中的w3wp线程池(ThreadPool)线程:
2Id:fb8.c5cSuspend:0Teb:7ffd9000Unfrozen

ChildEBPRetAddrArgstoChild

00c8ff247c821bf477e6611a0000017000c8ff80ntdll!KiFastSystemCallRet

00c8ff2877e6611a0000017000c8ff8000c8ff6cntdll!NtRemoveIoCompletion+0xc

00c8ff545a30249e0000017000c8ff7c00c8ff80kernel32!GetQueuedCompletionStatus+0x29

00c8ff8c5a3026bc00000000002585805a300000w3tp!THREAD_POOL_DATA::ThreadPoolThread+0x33

00c8ffa05a301db9000001020000000000000000w3tp!THREAD_POOL_DATA::ThreadPoolThread+0x24

00c8ffb877e66063002585800000000000000000w3tp!THREAD_MANAGER::ThreadManagerThread+0x39

00c8ffec000000005a301d800025858000000000kernel32!BaseThreadStart+0x34

闲置状态中的w3wp压缩(Compression)线程:
7Id:fb8.b20Suspend:0Teb:7ffaf000Unfrozen

ChildEBPRetAddrArgstoChild

017dfa847c82212477e6baa8000001d000000000ntdll!KiFastSystemCallRet

017dfa8877e6baa8000001d00000000000000000ntdll!NtWaitForSingleObject+0xc

017dfaf877e6ba12000001d0ffffffff00000000kernel32!WaitForSingleObjectEx+0xac

017dfb0c5a3b8147000001d0ffffffff00000000kernel32!WaitForSingleObject+0x12

017dffb877e66063000000000000000000000000w3core!HTTP_COMPRESSION::CompressionThread+0x126

017dffec000000005a3b80210000000000000000kernel32!BaseThreadStart+0x34

RPC线程
当有闲置的LRPC工作线程(workerthread)存在的时候,意味着我们可以处理更多的本地或者远程COM对象激活和本地COM函数调用。

有闲置RPC工作线程(workerthread)存在意味着我们可以处理更多的远程COM函数调用。

参看这篇文档来了解RPC线程模型:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/rpc/rpc/scalability.asp

闲置状态中的RPC工作(worker)线程:
29Id:fb8.7fcSuspend:0Teb:7ffa1000Unfrozen

ChildEBPRetAddrArgstoChild

02ddfeac7c821bf477e6611a0000007802ddff04ntdll!KiFastSystemCallRet

02ddfeb077e6611a0000007802ddff0402ddfef4ntdll!NtRemoveIoCompletion+0xc

02ddfedc77c604c30000007802ddff1402ddff04kernel32!GetQueuedCompletionStatus+0x29

02ddff1877c60655ffffffff02ddff6c02ddff70rpcrt4!COMMON_ProcessCalls+0xa1

02ddff8477c5f9f102ddffac77c5f7dd00090250rpcrt4!LOADABLE_TRANSPORT::ProcessIOEvents+0x117

02ddff8c77c5f7dd000902500000000000000000rpcrt4!ProcessIOEventsWrapper+0xd

02ddffac77c5de880008e61002ddffec77e66063rpcrt4!BaseCachedThreadRoutine+0x9d

02ddffb877e66063029515e80000000000000000rpcrt4!ThreadStartRoutine+0x1b

02ddffec0000000077c5de6d029515e800000000kernel32!BaseThreadStart+0x34

闲置状态中的LRPC工作(worker)线程:
33Id:fb8.b24Suspend:0Teb:7ffdb000Unfrozen

ChildEBPRetAddrArgstoChild

02e1fe187c821c5477c7538c0000013802e1ff74ntdll!KiFastSystemCallRet

02e1fe1c77c7538c0000013802e1ff7400000000ntdll!ZwReplyWaitReceivePortEx+0xc

02e1ff8477c5778f02e1ffac77c5f7dd0009d660rpcrt4!LRPC_ADDRESS::ReceiveLotsaCalls+0x198

02e1ff8c77c5f7dd0009d6600000000000000000rpcrt4!RecvLotsaCallsWrapper+0xd

02e1ffac77c5de880008e61002e1ffec77e66063rpcrt4!BaseCachedThreadRoutine+0x9d

02e1ffb877e6606305057c080000000000000000rpcrt4!ThreadStartRoutine+0x1b

02e1ffec0000000077c5de6d05057c0800000000kernel32!BaseThreadStart+0x34

其他COM线程
单线程组件必须被Host(Main)STA线程处理—这个线程是第一个被创建的COMSTA线程。

有闲置的STA线程存在的时候意味着我们可以处理更多的STA激活和函数调用。
参考来获取更多的信息:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncomser/html/comthread.asp。

HostSTA线程:
31Id:fb8.b3cSuspend:0Teb:7ff4e000Unfrozen

ChildEBPRetAddrArgstoChild

049cff147739c78d7739c7c0049cff5800000000ntdll!KiFastSystemCallRet

049cff3477694ff1049cff580000000000000000user32!NtUserGetMessage+0xc

049cff74776cf35b0000753077e6ba2002a40fe0ole32!CDllHost::STAWorkerLoop+0x72

049cff90776cf2a3049cffb8776b230777790438ole32!CDllHost::WorkerThread+0xc8

049cff98776b2307777904380000000002a40fe0ole32!DLLHostThreadEntry+0xd

049cffac776b237400000000049cffec77e66063ole32!CRpcThread::WorkerLoop+0x1e

049cffb877e6606302a40fe00000000000000000ole32!CRpcThreadCache::RpcWorkerThreadEntry+0x20

049cffec00000000776b235402a40fe000000000kernel32!BaseThreadStart+0x34

闲置的STA线程:
14Id:e5c.d90Suspend:1Teb:7ffac000Unfrozen

ChildEBPRetAddrArgstoChild

0140fdcc77f4372d77e41bfa000000030140fe1cSharedUserData!SystemCallStub+0x4

0140fdd077e41bfa000000030140fe1c00000001ntdll!NtWaitForMultipleObjects+0xc

0140fe7877d076f5000000030140fea000000000kernel32!WaitForMultipleObjectsEx+0x11a

0140fed477d077f5000000020140ff74ffffffffUSER32!RealMsgWaitForMultipleObjectsEx+0x13f

0140fef07563439d000000020140ff7400000000USER32!MsgWaitForMultipleObjects+0x1d

0140ff8477bc91ed000b6eb80000000000000000COMSVCS!CSTAThread::WorkerLoop+0x1e3

0140ffb877e4a99000268a580000000000000000msvcrt!_threadstartex+0x6f

0140ffec0000000077bc917e00268a5800000000kernel32!BaseThreadStart+0x34

备注:这不是一个完整的线程列表,但是上面这些可以在你分析导致你的进程没有响应的嫌疑犯的时候提供一些有用的信息。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: