前言
进程结构体EPROCESS(0x50和0x190)是2个链表,里面圈着当前进程的所有线程。
对进程断链,程序可以正常运行,原因是CPU执行与调度是基于线程的,进程断链只是影响一些遍历系统进程的API,并不会影响程序执行。
对线程断链也一样,断链后在Windbg或者OD无法看到被断掉的线程,但并不影响线程执行。
等待链表
线程有三种状态:就绪 等待 运行。
当线程调用了Sleep或者WaitForSingleObject等函数时,就挂到这个链表上。用下面这条命令可以查看等待链表。
kd> dd KiWaitListHead
KiWaitListHead是一个全局变量,里面存的是一个双向链表。阻塞中的线程一定在这个等待链表里。这个双向链表指向KTHREAD这个结构体的下面这个位置。
kd> dt _KTHREAD
+0x074 WaitListEntry : _LIST_ENTRY
+0x074 SwapListEntry : _SINGLE_LIST_ENTRY
33个链表
正在运行中的线程存储在KPCR中,就绪和等待的线程全在另外的33个链表中。一个等待链表,32个就绪链表
这些链表都使用了KTHREAD(0x60)的位置,也就是说线程在某一时刻,只能属于其中一个圈。
调度链表
就绪链表也称为调度链表,既然有32个链表,就要有32个链表头。在windbg中用下面的命令查看调度链表
kd> dd KiDispatcherReadyListHead L70
KiDispatcherReadyListHead是一个全局变量,存储了32个链表的链表头。那么为什么等待链表只有1个,而调度链表有32个呢。原因在于运行中的线程是有线程优先级的,这32个链表里面存储的就是不同的优先级的线程。
版本差异
XP只有32个圈,也就是说上面这个数组只有一个,多核也只有一个。W7也是一样的只有一个圈。如果是64位,那就有64个圈。
服务器版本:KiWaitListHead整个系统只有一个,但KiDispatcherReadyListHead这个数组有几个CPU就有几组
总结
- 正在运行的线程在KPCR中
- 准备运行的线程在32个调度链表里,KiDispatcherReadyListHead是个数组存储了这32个链表头
- 等待状态的线程存储在等待链表里,KiWaitListHead存储链表头
数组存储了这32个链表头 - 等待状态的线程存储在等待链表里,KiWaitListHead存储链表头
- 这些圈都挂在同一个相同的位置KTHREAD结构体