《Windows via C/C++》学习笔记 —— 线程优先级【转】

转自:http://www.cnblogs.com/wz19860913/archive/2008/08/04/1259807.html



  每个线程都有一个“优先级”,范围是0~31,0为最低优先级,31为最高优先级。当系统决定哪个线程需要调度的时候,首先查看是否存在优先级为31的可调度线程,如果存在,就从中选择一个进行调度。当该线程的时间片到达之后,系统查看是否存在另一个优先级为31的可调度线程,如果存在,就调度它。

  只要有一个可调度的优先级为31的线程存在,那么系统绝对不会调度优先级为0~30的线程,这样会导致其他线程“饥饿”。

  高优先级线程往往“打断”低优先级线程的执行。比如,当一个优先级为15的线程正在运行,如果此时系统发现一个优先级比15高的线程可以调度,那么该高优先级线程会“打断”那个低优先级线程的执行,哪怕低优先级的时间片才过了一半。

  另外,当系统引导的时候,系统创建一个特殊的线程,称为“zero page”(0页)线程,该线程是整个系统中唯一一个优先级为0(最低)的线程。当系统没有任何线程需要执行的时候,该线程负责将系统中所有RAM页面清零(也就是资源回收)。

  线程优先级有一个抽象层的概念。

  由于一些历史的原因,微软并没有将线程调度程序的行为完全固定下来。微软没有让应用程序充分利用调度程序的特性。微软宣称这个调度程序的行为是变化,在编程的时候需要注意。

  由这几点可见,你的应用程序可以有自己的调度特性。

  Windows API充分反映了系统调度的一个抽象层。如此,就不会直接与系统的调度程序通信,相反,可以调用API函数,根据系统的版本的不同转换这些参数。这一层,就是线程优先级的抽象层。

  下面详细叙述这个抽象层究竟有哪些内容:

  对于进程而言,Windows有一个“优先级类”的概念。这些优先级类作用与进程中的所有线程。Windows 2000/XP/2003/Vista支持6个“优先级类”:

1、Real-time:实时

2、High:高

3、Above normal:高于标准

4、Normal:标准

5、Below normal:低于标准

6、Idle:空闲。

  一个进程应该避免使用“实时”优先级类,因为使用该优先级类会导致其他进程中的线程很难被调度,甚至会打断或者抢占系统线程的执行。“高”优先级类也应该尽量避免,除非有特殊的工作需要使用这个优先级。

  当一个进程的“优先级类”被确定以后,就只需要考虑该进程内部各个线程之间的优先级关系。

  对于进程中的线程而言,有一个“相对线程优先级”的概念,这可以决定一个进程中多个线程之间的优先级关系。

  Windows支持7种“相对线程优先级”:

1、Time-critical:关键时间(最高的相对线程优先级)

2、Heightest:最高(翻译是这么翻译,但是并不是最高的相对线程优先级)

3、Above normal:高于标准

4、Normal:标准

5、Below normal:低于标准

6、Lowest:最低(翻译是这么翻译,但是并不是最低的相对线程优先级)

7、Idle:空闲

  这里并没有提到有关0~31的优先级的任何内容。开发者从来不用具体设置一个线程的优先级,也就是不需要将一个线程优先级设置为0~31中的一个。操作系统负责将“优先级类”和“相对线程优先级”映射到一个具体的优先级上。这种映射方式,是随Windows版本的不同而不同的。

  以下是Windows 2000/XP/2003/Vista的线程优先级映射方式(书上只说是Vista,但是对比本书第四版,可知2000和Vista是一样的):


线程相对

优先级


进程优先级类


Idle


Below Normal


Normal


Above Normal


High


Real-Time


Time-critical


15


15


15


15


15


31


Highest


6


8


10


12


15


26


Above normal


5


7


9


11


14


25


Normal


4


6


8


10


13


24


Below normal


3


5


7


9


12


23


Lowest


2


4


6


8


11


22


Idle


1


1


1


1


1


16

  仔细查看该表,现在知道为什么最好不要将“进程优先级类”设置为“实时”了吧,因为一个进程如果具有“实时”的优先级类,那么该进程中的所有线程的优先级(最低也有16)比任何具有其他优先级类的进程中的线程的优先级(最高只有15)都要高。这样会导致其他优先级类低于“实时”的进程中的线程无法得到调度。

  要注意的是,“优先级类”是一个抽象的概念,是对于一个进程而言的,但是不是说进程是可以调度的,只有线程是可以调度的。微软提出这个概念,仅仅只是为了帮助你将它与调度程序的内部运行的情况区分起来。“优先级类”应该是可以影响一个进程中所有线程的优先级的。

  上面讲了有关线程优先级的内容,包括线程的“具体优先级”,“优先级抽象层”的内容(进程“优先级类”、“线程相对优先级”等)。

  下面主要讲述如何在编程中设置线程的优先级:

  一个进程,往往关联一个“优先级类”,你可以在CreateProcess函数的fdwCreate参数中设置这个优先级类的具体内容,可以有6种选择,对于6种优先级类:

1、REALTIME_PRIORITY_CLASS:Real-time,实时优先级类

2、HIGH_PRIORITY_CLASS:High,高优先级类

3、ABOVE_NORMAL_PRIORITY_CLASS:Above normal,高于标准

4、NORMAL_PRIORITY_CLASS:Normal,标准

5、BELOW_NORMAL_PRIORITY_CLASS:Below normal:低于标准

6、IDLE_PRIORITY_CLASS:Idle,空闲

  你也可以更改一个特定的进程优先级类,通过呼叫SetPriorityClass函数可以到达这个目的。

BOOL SetPriorityClass(
   HANDLE hProcess,     //指定的进程句柄
   DWORD fdwPriority);     //优先级类(对应上面6种取值)

  例如,下面的代码设置当前进程的优先级类为空闲:

SetPrioriytClass(GetCurrentProcess(), IDLE_PRIORITY_CLASS);

  当然,可以获得某一个进程的优先级类,通过呼叫GetPriorityClass函数:

DWORD GetPriorityClass(HANDLE hProcess);

  该函数返回的值就是对应6个优先级类的值中的一个。

  当一个线程被创建,它的“线程相对优先级”默认为normal(标准)。CreateThread函数没有提供设置线程相对优先级的功能。可以调用SetThreadPriority函数设置一个线程的相对优先级。

BOOL SetThreadPriority(
   HANDLE hThread,     //指定的线程句柄
   int nPriority);     //线程相对优先级(取值对应如下)

  该函数接受一个线程句柄和线程相对优先级取值,设置对应的线程的相对优先级。该线程相对优先级取值如下:

1、THREAD_PRIORITY_TIME_CRITICAL:Time-critical,关键时间(最高)

2、THREAD_PRIORITY_HIGHEST:Highest,最高(其实是“次高”)

3、THREAD_PRIORITY_ABOVE_NORMAL:Above normal,高于标准

4、THREAD_PRIORITY_NORMAL:Normal,标准

5、THREAD_PRIORITY_BELOW_NORMAL:Below normal,低于标准

6、THREAD_PRIORITY_LOWEST:Lowest,最低(其实是“次低”)

7、THREAD_PRIORITY_IDLE:Idle,空闲(最低)

  你可以呼叫GetTreadPriotiry函数取得一个特定线程的相对优先级。

int GetThreadPriority(HANDLE hThread);     //函数返回上述7个取值

  为了创建一个线程相对优先级不是标准的线程,比如要创建一个高于标准的线程,你可以传递CREATE_SUSPENDED参数给CreateThread,从而创建一个起始状态为“挂起”的线程,然后调用SetThreadPriority函数设置该线程的相对优先级,然后调用ResumeThread函数恢复该线程的运行。代码如下:

DWORD dwThreadID;
HANDLE hThread = CreateThread(NULL, 0, ThreadFunc, NULL, CREATE_SUSPENDED, &dwThreadID);
SetThreadPriority(hThread, THREAD_PRIORITY_ABOVE_NORMAL);
ResumeThread(hThread);
CloseHandle(hThread);

  操作系统会动态地提高线程的基础优先级等级(0~31),一般是为了响应一些I/O事件。

  有的时候,系统动态地提高线程优先级会带来不便。你可以呼叫SetProcessPriorityBoost和SetThreadPriorityBoost函数来通知系统是否需要动态提高线程优先级。

BOOL SetProcessPriorityBoost(HANDLE hProcess, BOOL bDisablePriorityBoost);
BOOL SetThreadPriorityBoost(HANDLE hThread, BOOL bDisablePriorityBoost); 

  这两个函数的第二个参数用于通知系统是否要动态提高指定进程的优先级类和指定线程的相对优先级。

  也可以使用以下两个函数得到这些信息:

BOOL GetProcessPriorityBoost(HANDLE hProcess, PBOOL pbDisablePriorityBoost);
BOOL GetThreadPriorityBoost(HANDLE hThread, PBOOL pbDisablePriorityBoost);
时间: 2024-12-29 23:48:27

《Windows via C/C++》学习笔记 —— 线程优先级【转】的相关文章

【APUE】关于windows多线程编程的学习笔记

保证在某一时刻只有一个线程对数据进行操作的基本方法: (1)关中断:通过关闭时钟中断来停止线程调度(不现实) (2)数学互斥方法:Peterson算法 bakery算法 (3)操作系统提供的互斥方法:临界区.互斥量.信号量等(windows) (4)cpu原子操作:把一些常用的指令设计成了原子指令,在windows上面也被称为原子锁 [APUE]关于windows多线程编程的学习笔记

多线程编程学习笔记——线程同步(三)

接上文 多线程编程学习笔记——线程同步(一) 接上文 多线程编程学习笔记——线程同步(二) 七.使用Barrier类 Barrier类用于组织多个线程及时在某个时刻会面,其提供一个回调函数,每次线程调用了SignalAndWait方法后该回调函数就会被执行. 1.代码如下: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; //

windows下scrapy框架学习笔记—'scrapy' 不是内部或外部命令

最近几天在深入的学习scrapy框架,但是装完各种需要的基础包之后却发现scrapy命令在别的路径下都用不了,我一开始是把python安装在F:\Python路径下的,安装了scrapy后它默认都会安装在这个路径下,scrapy在路径F:\Python\Scripts路径下,我的scrapy命令只能在此路径下用,因此创建什么工程也都只能在此文件下. 想了一下它的工作原理:它在F:\Python\Scripts路径下,就会在Scripts文件下存在一个scrapy批处理文件,那么在DOS下想要命令

[转]Windows平台下Makefile学习笔记

Windows平台下Makefile学习笔记(一) 作者:朱金灿 来源:http://blog.csdn.net/clever101 决心学习Makefile,一方面是为了解决编译开源代码时需要跨编译平台的问题(发现一些开源代码已经在使用VS2010开发,但我还没安装VS2010,我想在VS2008下编译这些代码):另一方面源码在服务器端编译的话,使用IDE的方式编译还是不太方便. 本文主要分为三部分:第一部分讲述namke工具使用makefile的用法:第二部分讲述makefile的主要语法:

windows内核对象管理学习笔记

目前正在阅读毛老师的<windows内核情景分析>一书对象管理章节,作此笔记. Win内核中是使用对象概念来描述管理内核中使用到的数据结构.此对象(Object)均是由对象头(Object Header)组成,实际上由于对象头概念的特殊结构,还有些可选成分.于是一个对象实际上是分为三部分. OBJECT_HEADER对象头. 数据本体(比如文件对象File Object.Event等) 附加信息(比如Object Header Name Info等) 结构如下: //摘录自 Reactos代码

多线程编程学习笔记——线程池(一)

接上文 多线程编程学习笔记——线程同步(一) 接上文 多线程编程学习笔记——线程同步(二) 接上文 多线程编程学习笔记——线程同步(三) 创建多线程操作是非常昂贵的,所以每个运行时间非常短的操作,创建多线程进行操作,可能并不能提高效率,反而降低了效率. 如果你有非常多的执行时间非常短的操作,那么适合作用线程池来提高效率,而不是自行创建多线程. 线程池,就是我们先分配一些资源到池子里,当我们需要使用时,则从池子中获取,用完了,再放回池子里. .NET中的线程池是受CLR管理的,TheadTool类

JavaSE中线程与并行API框架学习笔记——线程为什么会不安全?

前言:休整一个多月之后,终于开始投简历了.这段时间休息了一阵子,又病了几天,真正用来复习准备的时间其实并不多.说实话,心里不是非常有底气. 这可能是学生时代遗留的思维惯性--总想着做好万全准备才去做事.当然,在学校里考试之前当然要把所有内容学一遍和复习一遍.但是,到了社会里做事,很多时候都是边做边学.应聘如此,工作如此,很多的挑战都是如此.没办法,硬着头皮上吧. 3.5 线程的分组管理 在实际的开发过程当中,可能会有多个线程同时存在,这对批量处理有了需求.这就有点像用迅雷下载电视剧,假设你在同时

Python 学习笔记 - 线程(1)

这是第一篇Python多线程的学习笔记,看看什么是多线程,以及如何创建他. 之前Python写的脚本程序里面,我们用到的都是单进程单线程的操作. 例如 传统的单进程,单线程的程序 import time def f1(arg,):     time.sleep(5)     print(arg) for i in range(10):     f1(i) 然而很多时候,我们需要并发的同时处理多个任务,举个例子,一个播放软件在放电影的时候,他需要同时播放图形,声音,字幕,这个时候他就创建了一个播放

Python 学习笔记 - 线程(2)

前面学习了线程基本的概念和创建线程的两种方法,现在看看多线程如何处理竞争条件(racing condition)的问题. 比如说,下面的例子中 我使用了第二种创建的方式,自定义一个类,继承Thread类,然后自定义run()来执行我的方法.在这个run方法里面,每次都对全局变量加1 在主线程里面,他调用一个自己定义的函数,在这个函数里面创建了5000个线程:每个线程都加入一个列表,然后对每个对象都使用join,这是确保主线程等着直到所有子线程完成.最后输出结果 import time impor