Windows核心编程学习笔记(14)--进程和线程的优先级

Drecik学习经验分享

转载请注明出处:http://blog.csdn.net/drecik__/article/details/8095467

 

1. 进程优先级

Windows支持6个优先级类,从小到大分别为:idle,blow normal,normal,above normal,high,real-time。其中normal是在ui常用的优先级类,为99%的用户使用。

  • real-time:此进程中的线程必须立即响应事件,执行实时任务,此进程中的线程还会抢占操作系统组件的CPU时间,使用需极为小心。
  • high:此进程中的线程必须立即响应事件,执行实时任务,任务管理器运行在这一级,所以可以通过它结束失控的进程。
  • above normal:此进程的线程运行在normal和high之间。
  • normal:此进程中的线程无需特殊的调度。
  • below normal:此进程中的线程运行在normal和idle之间。
  • idle:此进程中的线程在系统空闲时运行,屏幕保护程序,后台使用程序和统计数据收集软件通常使用该进程。

只有在绝对必要的时候才使用high优先级类,应该极可能避免使用real-time优先级类,因为real-time的进程会抢占操作系统组件的CPU时间,可能会阻止必要的磁盘I/O和网络通信,而且键盘和鼠标输入也无法及时的处理,只有充分的理由才使用real-time优先级。

注意:进程优先级的只是一个概念,进程是无法调度的,能调度的只有线程。

2. 线程优先级

首先说下线程优先级的调度模式:

在系统中每个线程都被赋予了0(最低)~31(最高)的优先级数,当系统决定哪个线程分配时,他会以优先级从大到小的来查找可供调度的线程来给他分配CPU,所以一个线程有比它优先级更高的线程可以被调度时,将导致该线程不会被调度,我们称这种情况饥饿(操作系统会动态的提高该线程优先级,关于动态提高优先级在后面讲述)。

还有一点就是较高优先级线程总是会抢占较低优先级的进程,无论较低优先级进程是否在执行。

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

 

接下来讲操作系统怎么支持线程优先级:

Windows支持7个相对线程优先级,从小到大分别为:idle,lowest,blow normal,normal,highest,time-critical。

注意我们这里没有提及0~31这个线程的优先级值,因为应用程序开发人员无需处理这个,线程的优先级值是用进程优先级类和相对线程优先级来确定的,以下表格给出来Windows Vista这个映射的具体情况:

从表中可以清楚的看到线程的优先级值与进程优先级类和相对线程优先级有一一的映射关系,但是这个不同的windows版本可能有所不同。

3. 优先级编程

  • 进程优先级编程

进程优先级可以在CreateProcess时,给参数dwCreationFlags参数(详情见我之前的博文)传入需要的优先级,下面给出优先级标识符:

REALTIME_PRIORITY_CLASS

HIGH_PRIORITY_CLASS

ABOVE_NORMAL_PRIORITY_CLASS

NORMAL_PRIORITY_CLASS

BELOW_NORMAL_PRIORITY_CLASS

IDLE_PRIORITY_CLASS

根据标示符单词可以很好的理解他们的意思,这里不再解释

进程运行的时候可以使用SetPriorityClass来改变优先级:

BOOL SetPriorityClass(
	HANDLE hProcess,		// 进程句柄;
	DWORD dwPriorityClass	// 优先级标识符;
	);


有了设置当然后获得,使用GetPriorityClass获得进程优先级:

DWORD GetPriorityClass(
	HANDLE hProcess		// 进程句柄,返回优先级标识符;
	);


最后两种是利用操作系统软件来改变进程优先级:

第一种是在cmd里面启动进程时使用START命令调用进程,在调用的时候可以指定一个优先级,例如:

c:\>START /LOW CALC.EXE

该命令以idle优先级运行一个计算器,同样还有/BELOWNORMAL, /NROAM, /ABOVENORMAL, /HIGH, /REALTIME

第二种是使用任务管理器,右键单机任务管理器上面的进程,可以在设置优先级菜单中指定优先级。

  • 线程优先级编程

 线程优先级可以使用SetThreadPriority进行设置和GetThreadPriority进行获取:

BOOL SetThreadPriority(
	HANDLE hThread,		// 线程句柄;
	int nPriority		// 优先级标识符;
	);

int GetThreadPriority(
	__in HANDLE hThread	// 线程句柄,返回优先级标识符;
	);


线程标识符可以是下列值,分别对应一个相对线程优先级:

THREAD_PRIORITY_TIME_CRITICAL

THREAD_PRIORITY_HIGHEST

THREAD_PRIORITY_ABOVE_NORMAL

THREAD_PRIORITY_NORMAL

THREAD_PRIORITY_BELOW_NORMAL

THREAD_PRIORITY_LOWEST

THREAD_PRIORITY_IDLE

注意:改变优先级的时候需要挂起线程

4. 动态提升线程优先级

系统通过线程的相对优先级加上线程所属进程的优先级来确定线程的优先级,该优先级称为基本优先级。

有些时候系统会动态提升一个线程的优先级,通常是为了响应某种I/O实现,比如窗口消息或者磁盘读取

例如:在high优先级进程中的一个normal线程,基本优先级值为13,如果用户敲击一个键,在该线程队列中放入WM_KEYDOWN消息,键盘设备驱动程序使系统临时提升线程的优先级,可能会提升2,变为15。线程在优先级为15时分的一个时间片,时间片结束后优先值减1,在下一个时间片结束后又将减1,以后将保持为13进行执行。

注意,线程的当前优先级不会低于进程的基本优先级。

系统只提升优先级值为1~15的线程,这个范围被称为动态优先级范围,系统不会把线程优先级值提升到实时范围(高于15),系统也不能提升实时范围的线程。

应用程序可以使用下面函数来获取当前是否进行动态提升和设置是否允许动态提升:

// 对一个进程中的所有线程进行指定;
BOOL SetProcessPriorityBoost(
	HANDLE hProcess,			// 进程句柄;
	BOOL bDisablePriorityBoost	// 是否允许动态提升;
	);
BOOL SetThreadPriorityBoost(
	HANDLE hThread,				// 线程句柄;
	BOOL bDisablePriorityBoost	// 是否允许动态提升;
	);

// 同样有获取是否允许动态提升;
BOOL GetProcessPriorityBoost(
	HANDLE hProcess,			// 进程句柄;
	PBOOL  pDisablePriorityBoost// 返回是否允许动态提升;
	);
BOOL GetThreadPriorityBoost(
	HANDLE hThread,
	PBOOL pDisablePriorityBoost
	);


另一种情况,当一个线程已经准备好了,但是出于饥渴状态(优先级比它高的线程正在执行),当出于这个状态3到4秒之后,系统会动态的将该线程提升到15,并允许它运行两个时间片,时间片结束后,线程恢复到原来的基本优先级。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章