进程线程006 Windows线程切换-线程优先级

内容回顾

之前我们已经了解过,有三种情况会导致线程切换:

  1. 当前线程主动调用API:API函数–>KiSwapThread–>KiSwapContext–>SwapContext
  2. 当前线程的时间片到期:KiDispatchInterrrupt–>KiQuantumEnd–>KiSwapContext–>SwapContext
  3. 有备用线程:KiDispatchInterrrupt–>SwapContext

KiSwapContext和KiQuantumEnd函数中都是通过KiFindReadyThread来找下一个要切换的线程,这次要解决的问题是KiFindReadyThread是根据什么条件来选择下一个要执行的线程。

调度链表

kd> dd KiDispatcherReadyListHead
8055bc20  8055bc20 8055bc20 8055bc28 8055bc28
8055bc30  8055bc30 8055bc30 8055bc38 8055bc38
8055bc40  8055bc40 8055bc40 8055bc48 8055bc48
8055bc50  8055bc50 8055bc50 8055bc58 8055bc58
8055bc60  8055bc60 8055bc60 8055bc68 8055bc68
8055bc70  8055bc70 8055bc70 8055bc78 8055bc78
8055bc80  8055bc80 8055bc80 8055bc88 8055bc88
8055bc90  8055bc90 8055bc90 8055bc98 8055bc98

线程的调度链表一共有32个,这32个是按照不同的级别存放在一起的。例如线程级别为0的挂到0号链表里,线程级别为1的挂到1号链表里。

KiFindReadyThread查找线程的方式—>按照优先级进行查找:31…30…29…28。也就是说,在本次查找中,如果级别31的链表里面有线程,那么就不会查找级别为30的链表

这并不意味着线程级别高的线程执行完了才能执行线程级别低的线程,在查找的时候,每次只会查找线程级别最高的那个线程,但是高级别的线程在执行的时候,如果调用了API或者CPU时间片到期,低级别的线程仍然是有机会执行的。

如何高效查找

调度链表有32个,每次从头查找效率太低,所以Windows在这方面做了一个优化。

Windows定义了一个DWORD类型的变量来记录:

在这里插入图片描述

DWORD类型的变量有32位,里面的每一位分别对应当前某一个链表里面是否有正在等待调度的线程。

当向调度链表中挂入或者删除某个线程的时候,会判断当前级别的链表是否为空,为空则将DWORD变量对应位置置0,否则置1

当某一个时刻,这个DWORD类型的变量转换为二进制的值如上图的时候,意味着在32个链表里,线程级别为30的链表里有等待调度的线程,线程级别为29的链表里也是有等待调度的线程。其他的链表则没有等待调度的线程。

这个变量:_kiReadySummary

如果没有就绪线程怎么办

在KPCR里面有一个子结构体PrcbData,这个子结构体有三个重要的成员,如下

PrcbData:
+0x004 CurrentThread    : Ptr32 _KTHREAD
+0x008 NextThread       : Ptr32 _KTHREAD
+0x00c IdleThread       : Ptr32 _KTHREAD 
  • CurrentThread:当前正在运行的线程
  • NextThread:下一次准备运行的线程,也就是备用线程
  • IdleThread:空闲线程,当前的CPU查找调度链表发现里面已经没有需要调度的线程的时候,就会运行这个线程

在这里插入图片描述

下面通过代码论证,首先找到KiFindReadyThread

在这里插入图片描述

交叉引用找到上一层调用它的函数,以KiSwapThread为例

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wl5LlG80-1581510940435)(assets/1581478367459.png)]

这里调用了KiFindReadyThread查找一个就绪线程,然后判断是否为空,如果为空则继续往下执行

.text:00429162                 mov     eax, [esi+0Ch] 

这里的esi就是PrcbData结构体,+0xC的位置就是IdleThread,这里取出IdleThread放到eax里

.text:0042916C                 or      _KiIdleSummary, edx

接着修改这个全局变量

在这里插入图片描述

然后继续调用KiSwapContext进行线程切换,这个时候切换的目标线程就是IdleThread

发布了99 篇原创文章 · 获赞 89 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/qq_38474570/article/details/104286223