Windows核心编程笔记(七) 线程调度 优先级 关联性

来源:互联网 发布:vb log无法识别 编辑:程序博客网 时间:2024/05/23 21:56

首先线程与系统时钟间隔参见http://blog.csdn.net/wangpengk7788/article/details/54287947

在抢占式多任务操作系统中,线程的运行是有限制的,系统会调度一个线程在一个时间块内占用CPU,在时间到了之后将线程的上下文(CONTEXT结构,保存线程切换前的CPU个寄存器的值)保存到线程内核对象中,从另一个可调度线程的CONTEXT中获取属于它的CPU各寄存器的值,设置CPU寄存器,执行该线程,这样重复着在不同的线程之间切换,保证每个可调度线程能得到执行时间。

        在我使用的64位WIN7中  GetSystemTimeAdjustment




DWORD SuspendThread(HANDLE hThread   );  返回线程上次挂起的次数

挂起一个线程,一个线程最多可以挂起, 一个线程最多可以挂起MAXIMUM_SUSPEND_COUNT  (127)次, 被挂起的线程不参与线程调度

DWORD ResumeThread(HANDLE hThread   ); 返回上次挂起次数

递减线程内核对象中 线程挂起计数,只有在挂起减到0时,线程才能恢复运行


进程不能挂起,除了在调试器处理WaitForDebugEvent时,被调试的进程所有线程会挂起。


Sleep函数


1、调用Sleep函数使线程挂起,线程放弃剩余的时间片

2、Sleep设置的挂起时间只是近似值,不保证会准时醒来

3、可以传入INFINITE线程永久挂起

4、传入0表示放弃当前使用的剩余时间片


SwitchToThread   让出时间片,可能调度给比自己优先级低的线程



可以在一段代码的之前使用GetThreadTime获取线程执行的时间,取前后时间的差 做为该段代码的执行时耗。


在VISTA中为线程分配CPU时间的方式发生了变化 ,在新的系统中使用处理器时间戳计时器TSC,在线程被调度程序暂停时,将计算此时TSC的值与线程开始时的TSC值之间的差,然后在线程执行时间上加上该差值,不计算中断时间。我们可以使用ReadTimeStampCounter宏来获取TSC的值。


GetThreadContext 获取线程的上下文,这里CONTEXT结构对熟悉汇编的看起来会很亲切。Windwos 还是提供了SetThreadContext函数,这是很强大的对于喜欢做一些比较另类和猥琐的事情的人,比如可以创建一个挂起的进程比如系统的计算器,把另一个执行文件,比如系统的记事本程序自己加载到这个挂起的进程空间中去,然后改变主线程的CONTEXT,设置成记事本程序主线程入口所需要的环境,那么就可以借尸还魂了。在任务管理器里看到的是一个计算器程序,实际运行的代码是记事本的。



线程的优先级

在Windows中线程的优先级为0-31,优先级高的线程优先被调度,只有在优先级高的线程都处于不可调度状态时,才递减调度其次优先级的线程,当较高优先级的线程占用了CPU时间,致使较低优先级的线程无法运行时成为饥饿,在多处理器上饥饿的情况发生的可能性很小,系统大多数线程都是不可调度的,例如线程调用了GetMessage等待获取消息,如果这时消息队列中没有消息,系统会暂停这个线程,并将CPU分配给另一个等待调度的线程。

在较低优先级的线程被调度时,如果有较高优先级的线程已经处于可调度状态,系统会暂停较低优先级的线程,将CPU分给高优先级的线程,Windows的线程调度是抢占掠夺式的。

Windwos的进程优先级分为6个等级,可以通过SetPriorityClass来设置

BOOL WINAPI SetPriorityClass(  __in  HANDLE hProcess,  __in  DWORD dwPriorityClass);


                                                                dwPriorityClass对应的标志实际优先级值

优先级标志优先级值idle   (低)IDLE_PRIORITY_CLASS4Below (低于标准)BELOW_NORMAL_PRIORITY_CLASS normal (标准)NORMAL_PRIORITY_CLASS7或9Above (高于标准)ABOVE_NORMAL_PRIORITY_CLASS high (高)HIGH_PRIORITY_CLASS13realtime (实时)REALTIME_PRIORITY_CLASS

24



Windwos的线程有6个相对于进程的优先级,相对优先级使用 SetThreadPriority来设置


BOOL WINAPI SetThreadPriority(  __in  HANDLE hThread,  __in  int nPriority);


nPriority对应的标志在进程优先级的基础上调整

线程优先级等级标志优先级值idle (最低)THREAD_PRIORITY_IDLE如果进程优先级为realtime则调整为16,其它情况为1LOWEST 低THREAD_PRIORITY_LOWEST-2(在原有基础上-2)BELOW 低于标准THREAD_PRIORITY_BELOW_NORMAL-1(在原有基础上-1)NORMAL(标准)THREAD_PRIORITY_NORMAL不变(取进程优先级值)ABOVE 高于标准THREAD_PRIORITY_ABOVE_NORMAL+1(在原有基础上+1)HIGHEST(高)THREAD_PRIORITY_HIGHEST+2(在原有基础上+2)CRITICAL(最高)THREAD_PRIORITY_TIME_CRITICAL如果进程优先级为realtime则调整为31,其它情况为15


这些进程优先级和线程相对优先级在Windwos不同版本 所对应的优先级值得映射不有变化的。



当一个进程中的线程为了响应某种IO事件,比如窗口消息,磁盘读取,获取网络包,线程会在这时被系统动态提升为NORMAL级,且只能提升1~15级的线程。在线程提升优先级后的每个时间片内优先级会被递减,直到恢复原来的优先级。



可以使用SetProcessPriority 来设置是否允许系统动态提升线程优先级。使用GetProcessPriority来获取线程是否开启被提升。



调度IO请求优先级


在设置进程和线程优先级时可以为 这两个函数传入  对应的THREAD_MODE_BACKGROUND_BEGIN   PROCESS_MODE_BACKGROUND_BEGIN  让线程或进程进入低IO优先级状态,传入THREAD_MODE_BACKGROUND_END     PROCESS_MODE_BACKGROUND_END 进入NORMAL级状态。




CPU关联性



我们可以使用下满两个函数设置线程或进程运行于哪个CPU之上。dwProcessAffinityMask 用二进制位做掩码,比如3  代码运行在CPU0和CPU1上,5表示在CPU2和CPU0上

BOOL WINAPI SetProcessAffinityMask(  __in  HANDLE hProcess,  __in  DWORD_PTR dwProcessAffinityMask);
DWORD_PTR WINAPI SetThreadAffinityMask(  __in  HANDLE hThread,  __in  DWORD_PTR dwThreadAffinityMask);




0 0
原创粉丝点击