Windows核心编程——第7章 线程调度

来源:互联网 发布:公告管理系统源码 编辑:程序博客网 时间:2024/05/17 10:06

线程的挂起和恢复

        调用CreateProcessCreateThread函数时,系统将创建线程内核对象,并把挂起计数初始化为1,在线程初始化之后,CreateProcessCreateThread函数将查看是否有CREATE_SUSPENDED标志传入,如果有函数会返回并让新的线程处于挂起状态,否则函数会将线程的挂起计数挂起计数减为0,线程将成为可调度的。


        可以使用ResumeThread函数来恢复被挂起的线程,使其重新成为可以调度的线程,使用SuspendThread函数将一个线程挂起。而在调试状态下可以使用WaitForDebugEvent来挂起进程中所有线程,使用ContinueDebugEvent来恢复进程中的线程。


        OpenThread函数通过线程ID来返回其句柄,并使内核对象的使用计数递增1


        Sleep函数将使线程自己挂起一定长的时间,时间长度由参数决定,但是只是大约这么久,调用Sleep并传递参数INFINITE将导致系统永远不要调用这个进程,而传入参数0将告诉系统主调线程放弃时间片剩余部分,系统将重新选择线程执行,也可以继续执行Sleep这个线程。


        SwichToThread函数调用时,系统查看是否存在急需CPU时间的饥饿线程,如果没有的话,SwichToThread将立即返回,如果存在的话,SwichToThread将调度该线程,运行一个时间片之后系统调度程序恢复正常运行。与Sleep(0)类似,差别就在SwichToThread允许执行低优先级线程,而Sleep会立即重新调度主调线程。


        GetThreadTimes可以获得线程的系统时间信息,下面这个函数可以确定执行一个复杂算法所需要的时间。


        GetProcessTimes可以获得进程的系统时间信息,返回的时间适用于一个指定进程中的所有线程,所返回的内核时间是所有线程在内核模式下所耗时间总和。


线程上下文CONTEXT结构分为几部分

l CONTEXT_CONTROL包含CPU的控制寄存器

l CONTEXT_INTEGER标识CPU整数寄存器

l CONTEXT_FLOATING_POINT标识CPU的浮点寄存器

l CONTEXT_SEGMENTS标识CPU的段寄存器

l CONTEXT_DEBUG_REGISTERS标识CPU的调试寄存器

l CONTEXT_EXTENDED_REGISTERS标识CPU的扩展寄存器。

l CONTEXT_FULL被定义为CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS


        使用GetThreadContext函数可以获得一个CONTEXT结构,但是传给GetThreadContext之前需要使用上面的标志初始化ContextFlags,并且执行之前要使用SuspendThread挂起线程,GetThreadContext将返回用户模式线程上下文。


        使用SetThreadCOntext函数可以将一个上下文CONTEXT结构的内容写回线程内核对象中,但是使用这个函数进也应该初始化标志ContextFlags,并且暂停线程,否则结果无法预料。


进程和线程优先级


        每个线程都被赋予0~31的优先级数,系统确定要分配CPU时,会首先查看优先级31的线程,并以循环的方式进行调度,每次都会从最高的优先级调度开始。


        系统启动的时候会创建一个名为页面清零线程的特殊线程。这个线程优先级为0,是整个系统中的一个优先级为0的线程,在没有其它进程需要执行的时候,将系统内存中的所有闲置页面清零。


        进程优先级可以在调用CreateProcess时在fdwCreate参数中传入 需要的优先级,改变进程的优先级可以使用SetPriorityClass函数,获取进程优先级函数GetPriorityClass,使用SetThreadPriority来改变一个线程的相对优先级,使用GetThreadPriority来获得线程的相对优先级,如果想创建优先级非normal的新线程,需要先挂起线程,再SetThreadPriority设置线程的优先级,接着调用ResumeThread使线程成为可调度的。


        SetProcessPriorityBoost允许或禁止系统提升一个进程中所有线程的优先级,如果想对进程中的某个线程进行设置,则可以使用SetProcessPriorityBoost函数,它可以允许或禁止提升某个线程的优先级。


        SetFileInformationByHandle函数可以设置文件I/O请求权限,另外我们开发程序的时候应该尽量避免优先级逆转,尽量减少在normal和后台优先级线程之间使用共享同步对象,或者尽量不共享,以避免normal优先级线程因为后台优先级毛线拥有的锁而被阻塞,导致优先级逆转。


        应用GetSystemInfo来查询机器上CPU的数量,使用SetProcessAffinityMask来设置进程的关联性,使用GetProcessAffinityMask来返回进程的关联性掩码。如果要进行更细粒度的设置的话,可以使用SetThreadAffinityMask来对线程关联性进行设置,但是设置线程的硬关联将影响调度程序的调度方案,所以要给线程设置一个理想的空闲的CPU,可以使用函数SetThreadIdealProcessor来实现。