7线程的调度优先级和亲缘性(4)

2019-05-18 23:22

壳程序都具有极强的响应能力。实际上,即使低优先级线程在无限循环中暂停运行,也能显示E x p l o r e r的窗口。由于E x p l o r e r的线程拥有较高的优先级,因此执行无限循环的线程被抢占,E x p l o r e r让用户终止挂起进程的运行。E x p l o r e r的运行特性非常出色,大部分时间它的线程无事可做,不必占用C P U时间。如果情况不是如此,那么整个系统的运行速度就会慢得多,许多应用程序就不会作出响应。

应该尽可能避免使用实时优先级类。实际上Windows NT 3.1的早期测试版并没有向应用程序展示这个优先级类,尽管该操作系统支持这个类。实时优先级是很高的优先级,它可能干扰操作系统任务的运行,因为大多数操作系统线程均以较低的优先级来运行。因此实时线程可能阻止必要的磁盘I / O信息和网络信息的产生。此外,键盘和鼠标输入将无法及时得到处理,用户可能以为系统已经暂停运行。大体来说,必须有足够的理由才能使用实时优先级,比如需要以很短的等待时间来响应硬件事件,或者执行某些不能中断的短期任务。

注意 除非用户拥有“提高调度优先级”的权限,否则进程不能用实时优先级类来运行。凡是被指定为管理员或特权用户的用户,均默认拥有该权限。

当然,大多数进程都属于正常优先级类。低于正常和高于正常的优先级类是Windows 2000中的新增优先级。M i c r o s o f t增加这些优先级类的原因是,有若干家公司抱怨现有的优先级类无法提供足够的灵活性。

一旦选定了优先级类之后,就不必考虑你的应用程序与其他应用程序之间的关系,只需要集中考虑你的应用程序中的各个线程。Wi n d o w s支持7个相对的线程优先级:即空闲、最低、低于正常、正常、高于正常、最高和关键时间优先级。这些优先级是相对于进程的优先级类而言的。大多数线程都使用正常线程优先级。表7 - 5描述了这些相对的线程优先级。

表7-5 相对的线程优先级

相对的线程优先级 关键时间 最高 描述 对于实时优先级类来说,线程在优先级3 1上运行,对于其他优先级类来说,线程在优先级1 5上运行 线程在高于正常优先级的上两级上运行 高于正常 线程在正常优先级的上一级上运行 正常 线程在进程的优先级类上正常运行 低于正常 线程在低于正常优先级的下一级上运行 最低 空闲 线程在低于正常优先级的下两级上运行 对于实时优先级类来说,线程在优先级1 6上运行对于其他优先级类来说,线程在优先级1上运行 概括起来说,进程是优先级类的一个组成部分,你为进程中的线程赋予相对线程优先级。这里没有讲到0到3 1的优先级的任何情况。应用程序开发人员从来不必具体设置优先级。相反,系统负责将进程的优先级类和线程的相对优先级映射到一个优先级上。正是这种映射方式,M i c r o s o f t不想拘泥不变。实际上这种映射方式是随着系统的版本的升级而变化的。

表7 - 6显示了这种映射方式是如何用于Windows 2000的,注意,Windows NT的早期版本和某些Windows 95和Windows 98版本采用了不同的映射方式。未来的Wi n d o w s版本中的映射方式也会变化。

例如,正常进程中的正常线程被赋予的优先级是8。由于大多数进程属于正常优先级类,而大多数线程属于正常线程优先级,因此系统中的大多数线程的优先级是8。

如果高优先级进程中有一个正常线程,该线程的优先级将是1 3。如果将进程的优先级类改为8,那么线程的优先级就变为4。如果改变了进程的优先级类,线程的相对优先级不变,但是它的优先级的等级却发生了变化。

表7-6 进程优先级类和线程相对优先级的映射

相对线程优先级 关键时间 最高 高于正常 正常 低于正常 最低 空闲 空闲 1 5 6 5 4 3 2 1 低于正常 1 5 8 7 6 5 4 1 5 1 0 9 8 7 6 1 正常 高于正常 1 5 1 2 11 1 0 9 8 1 高 1 5 1 5 1 4 1 3 1 2 11 1 实时 3 1 2 6 2 5 2 4 2 3 22 1 6 注意,表7 - 6并没有显示优先级的等级为0的线程。这是因为0优先级保留供零页线程使用,系统不允许任何其他线程拥有0优先级。另外,下列优先级等级是无法使用的: 1 7、1 8、1 9、2 0、2 1、2 7、2 8、2 9和3 0。如果编写一个以内核方式运行的设备驱动程序,可以获得这些优先级等级,而用户方式的应用程序则不能。另外还要注意,实时优先级类中的线程不能低于优先级等级1 6。同样,非实时优先级类中的线程的等级不能高于1 5。

注意有些人常常搞不清进程优先级类的概念。他们认为这可能意味着进程是可以调度的。但是进程是根本不能调度的,只有线程才能被调度。进程优先级类是个抽象概念,M i c r o s o f t提出这个概念的目的,是为了帮助你将它与调度程序的内部运行情况区分开来。它没有其他目的。 注意一般来说,大多数时候高优先级的线程不应该处于可调度状态。当线程要进行某种操作时,它能迅速获得C P U时间。这时线程应该尽可能少地执行C P U指令,并返回睡眠状态,等待再次变成可调度状态。相反,低优先级的线程可以保持可调度状态,执行大量的C P U指令来进行它的操作。如果按照这些原则来办,整个操作系统就能正确地对用户作出响应。

7.9 程序的优先级

进程是如何被赋予优先级类的呢?当调用C r e a t e P r o c e s s时,可以在f d w C r e a t e参数中传递需要的优先级类。表7 - 7显示了优先级类的标识符。

表7-7 优先级类的标识类

优先级类 实时 高 标识符 R E A LT I M E _ P R I O R I T Y _ C L A S S H I G H _ P R I O R I T Y _ C L A S S 高于正常 A B O V E _ N O R M A L _ P R I O R I T Y _ C L A S S 正常 N O R M A L _ P R I O R I T Y _ C L A S S 低于正常 B E L O W _ N O R M A L _ P R I O R I T Y _ C L A S S 空闲 I D L E _ P R I O R I T Y _ C L A S S 创建子进程的进程负责选择子进程运行的优先级类,这看起来有点奇怪。让我们以E x p l o r e r为例来说明这个问题。当使用E x p l o r e r来运行一个应用程序时,新进程按正常优先级运行。E x p l o r e r不知道进程在做什么,也不知道隔多长时间它的线程需要进行调度。但是,一旦子进程运行,它就能够通过调用S e t P r i o r i t y C l a s s来改变它自己的优先级类:

BOOL SetPriorityClass(HANDLE hProcess, DWORD fdwPriority);

该函数将h P r o c e s s标识的优先级类改为f d w P r i o r i t y参数中设定的值。f d w P r i o r i t y参数可以是表7 - 7显示的标识符之一。由于该函数带有一个进程句柄,因此,只要拥有该进程的句柄和足够的访问权,就能够改变系统中运行的任何进程的优先级类。

一般来说,进程将试图改变它自己的优先级类。下面是如何使一个进程将它自己的优先级类设置为空闲的例子:

BOOL SetPriorityClass(GetCurrentProcess(), IDLE_PRIORITY_CLASS);

下面是用来检索进程的优先级类的补充函数:

DWORD GetPriorityClass(HANDLE hProcess);

正如你所期望的那样,该函数将返回表7 - 7中列出的标识符之一。

当使用命令外壳启动一个程序时,该程序的起始优先级是正常优先级。但是,如果使用S t a r t命令来启动该程序,可以使用一个开关来设定应用程序的起始优先级。例如,在命令外壳输入下面的命令可使系统启动C a l c u l a t o r,并在开始时按空闲优先级来运行它:

C:\\>START /LOW CALC.EXE

S t a r t命令还能识别/ B E L O W N O R M A L、/ N O R M A L、/ A B O V E N O R M A L、/ H I G H和/ R E A LT I M E等开关,以便按它们各自的优先级启动执行一个应用程序。当然,一旦应用程序启动运行,它就可以调用S e t P r i o r i t y C l a s s函数,将它自己的优先级改为它选择的任何优先级。

Windows 98的S t a r t命令并不支持这些开关中的任何一个。Windows 98命令外壳启动的进程总是使用正常优先级类来运行。

Windows 2000的Task Manager 使得用户可以改变进程的优先级类。图7 - 2显示了Ta s kM a n a g e r的P r o c e s s e s选项卡,它显示了当前运行的所有进程。Base Pri列显示了每个进程的

优先级类。可以改变进程的优先级类,方法是选定一个进程,然后从上下文菜单的Set Priority(设置优先级)子菜单中选择一个选项。

图7-2 Windows Task Manager 对话框

当一个线程刚刚创建时,它的相对线程优先级总是设置为正常优先级。我总感到有些奇怪,C r e a t e T h r e a d没有为调用者提供一个设置新线程的相对优先级的方法。若要设置和获得线程的相对优先级,必须调用下面的这些函数:

BOOL SetThreadPriority(HANDLE hThread, int nPriority);

当然,h T h r e a d参数用于标识想要改变优先级的单个线程, n P r i o r i t y参数是表7 - 8列出的7个标识符之一。

表7-8 线程相对优先级的标识符常量

相对线程优先级 标识符常量 关键时间 T H R E A D _ P R I O R I T Y _ T I M E _ C R I T I C A L 最高 T H R E A D _ P R I O R I T Y _ H I G H E S T 高于正常 T H R E A D _ P R I O R I T Y _ A B O V E _ N O R M A L 正常 T H R E A D _ P R I O R I T Y _ N O R M A L 低于正常 T H R E A D _ P R I O R I T Y _ B E L O W _ N O R M A L 最低 空闲 T H R E A D _ P R I O R I T Y _ L O W E S T T H R E A D _ P R I O R I T Y _ I D L E 下面是检索线程的相对优先级的补充函数:

int GetThreadPriority(HANDLE hThread);

该函数返回表7 - 8列出的标识符之一。

若要创建一个带有相对优先级为空闲的线程,可以执行类似下面的代码:

DWORD dwThreadID;

HANDLE hThread = CreateThread(NULL, 0, ThreadFunc, NULL, CREATE_SUSPENDED, &dwThreadID);

SetThreadPriority(hThread, THREAD_PRIORITY_IDLE);

ResumeThread(hThread); CloseHandle(hThread);

注意,C r e a t e T h r e a d函数创建的新函数带有的相对优先级总是正常优先级。若要使线程以空闲优先级来运行,应该将C R E AT E _ S U S P E N D E D标志传递给C r e a t e T h r e a d函数,这可以防止线程执行任何代码。然后可以调用S e t T h r e a d P r i o r i t y,将线程的优先级改为相对空闲优先级。这时可以调用R e s u m e T h r e a d,使得线程成为可调度的线程。你不知道线程何时能够获得C P U时间,但是调度程序会考虑这样一个情况,即该线程拥有一个空闲优先级。最后,可以关闭新线程的句柄,一旦线程终止运行,内核对象就能被撤消。 注意Wi n d o w s没有提供返回线程的优先级的函数。这是故意进行的。记住,M i c r o s o f t保留了随时修改调度算法的权利。你不会设计需要调度算法专门知识的应用程序。如果坚持使用进程优先级类和相对线程优先级,你的应用程序不仅现在能够顺利地运行,而且在系统的将来版本上也能很好地运行。

7.9.1 动态提高线程的优先级等级

通过将线程的相对优先级与线程的进程优先级类综合起来考虑,系统就可以确定线程的优先级等级。有时这称为线程的基本优先级等级。系统常常要提高线程的优先级等级,以便对窗口消息或读取磁盘等I / O事件作出响应。

例如,在高优先级类进程中的一个正常优先级等级的线程的基本优先级等级是1 3。如果用户按下一个操作键,系统就会将一个W M _ K E Y D O W N消息放入线程的队列中。由于一个消息已


7线程的调度优先级和亲缘性(4).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:新课改背景下小学语文教师课堂教学评价语言探究-教育文档

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: