天天看点

《Windows核心编程》读书心得——线程(线程调度)(4)

l  CPU切换调度线程:

每个线程都有一个上下文(CONTEXT),保存在线程的内核对象中。它记录了线程上一次执行时CPU寄存器的状态。

大约每隔20ms,CPU会查看当前所有的线程,然后在可调度的线程中选择一个进行调度。CPU切换调度线程时,先将CPU寄存器写回线程上下文(这样,下次调度该线程,就能从上次停止的地方继续),停止运行原线程;检查剩下的可调度线程内核对象,选择另一个线程内核对象,将该线程上下文载入CPU寄存器。

查看和设置CONTEXT:

查看context:GetThreadContext()

设置context:SetThreadContext()

l  线程的挂起和恢复:

ResumeThread ():将挂起计数减1,当挂起计数为0,唤醒线程。

(若调用成功,返回线程的前一个挂起计数;否则,返回0xFFFFFFFF)

SuspendThread():将挂起计数加1,挂起线程。

Sleep():线程睡眠,让出时间来调度其他线程。

假如需要强制CPU停止调度当前线程,把时间片让给其他线程,可以使用Sleep(0)或SwitchToThread(),两者的区别如下:

Sleep():时间片只能让给优先级相同或更高的线程;

SwitchToThread():只要有可调度线程,即便优先级较低,也会让其调度。

l  两个从消息队列取消息的函数:

PeekMessage():从消息队列取一条消息,但不取走。

GetMessage():从消息队列取一条消息,并取走。

l  线程优先级:

优先级为0的线程:系统启动时,会创建一个优先级为0的“页面清零线程”,它只有在系统中没有其他可调度线程时,才能调度,用来清除内存中的闲置页面。

优先级在1 ~ 15之间的线程:一般用户模式下,线程的优先级都在该范围。

优先级在16 ~ 30之间的线程:一般是内核线程。

线程的抢占:

较高优先级的线程,总是会抢占较低优先级线程的处理时间。一般而言,较高优先级的线程大多数都是不可调度的,否则会长期占用CPU时间。

动态提升优先级:

如上文所述,线程都有一个基本优先级,其范围从0到31。线程的优先级一般保持在基本优先级附近,但不是固定的,因为系统可能在某些情况下暂时将该优先级提高。

例如:当系统检测到有线程处于饥饿状态3到4秒时,会暂时将该线程的优先级提升到15,并允许其执行两个时间片。当两个时间片执行完,会将其恢复到基本优先级。

(注意:系统只会提升优先级在1 ~ 15之间的线程,而且提升后优先级不会高于15,以防影响操作系统。同时,系统只能提升一个线程的优先级,而不能降低其优先级)

相关函数:

SetProcessPriorityBoost( …):是否允许对进程进行优先级提升;

SetThreadPriorityBoost( …):是否允许对线程进行优先级提升;

GetProcessPriorityBoost( …):当前是否启用进程优先级提升;

GetThreadPriorityBoost( …):当前是否启用线程优先级提升。

l  为线程指定CPU:

NUMA:

非统一内存访问计算机体系结构。由多个系统板组成,每个系统板都有自己的CPU和内存块。每个CPU可访问任何一块系统板的内存,但访问自己所在系统板的内存比较快,而访问其它板上内存特别慢。

为线程指定CPU的好处:

如上介绍的NUMA系统,应该指定一个进程中所有的线程运行在某块系统板上,这样才能保证该板上的CPU在调度这些线程时不会访问其它板上的内存,从而保证效率。此外,假如为线程分配固定的CPU,可以减少CPU时间片切换带来的时间开销,这在某些情况下也是有利于提高工作效率的。

相关函数:

SetProcessAffinityMask(HANDLE  hProcess, DWORD_PTR dwProcessAffinityMask):

(1)hProcess:要设置的进程。

(2)dwProcessAffinityMask:位掩码,表示可以在哪些CPU上运行。该参数每个二进制位表示一个CPU的状态,若某位为1,表示能在该位对应的CPU上运行本进程(例如,0x5表示可以在CUP0和CPU2上运行)。

GetProcessAffinityMask( …):返回进程关联性掩码。

SetThreadAffinityMask( …):设置线程关联性掩码。(用该函数指定CPU,则在线程内部不能使用sleep,否则会被其他CPU抢占资源,没能完全起到指定CPU的目的)

SetThreadIdealProcessor( …):设置线程的理想CPU(该函数第二个参数是0 ~ 31/63之间的数,表示理想CPU的编号)。用该函数设定了理想CPU,那么系统会优先选择该CPU来运行线程,同时当该CPU繁忙时,允许让线程在其它空闲CPU上运行,这样做效率更高。

继续阅读