Windows线程优先级提升策略

Windows线程优先级提升策略

 

Windows实现了一个基于优先级的抢先式多处理及调度系统。通常线程可在任何可用处理机上运行,但可限制某线程只能在某处理机上运行。要了解线程优先级的变化,首先我们应该清楚Windows对线程优先级的设置。

Windows的每个线程都有自己的状态,包括实际优先级、处理器亲和和帐号信息。调度程序采用了32级优先权方案以确定线程执行顺序。优先级分成两类:可变类和实时类。可变类包括0到15优先级的线程,实时类包括16到31优先级的线程。实时线程总是比系统中的其他线程先被调度,而且Windows从不改变实时线程的优先级。

可变优先级类型的线程有一个基优先级和一个动态优先级,同一个线程的动态优先级总比它的基优先级高。线程基优先级可在比父进程的基优先级小2或大2的范围内取值。内核周期性地调整一个线程的动态优先级,当一个线程等待一个I/O时,内核将该线程的动态优先级调高。一个受CPU制约的线程动态优先级较低,而受I/O制约的线程动态优先级则较高。

线程按其所属类型所确定的最初优先级而开始。线程优先权可以通过SetThreadPriority函数改变。该函数带有一个参数,以表示一个优先权与其类型的基本优先权的相互关系。

 

参数名

 

意义

 

THREAD_PRIORITY_LOWEST

 

base-2

 

THREAD_PRIORITY_BELOW_NORMAL

 

base-1

 

THREAD_PRIORITY_NORMAL

 

base

 

THREAD_PRIORITY_ABOVE_NORMAL

 

base+1

 

THREAD_PRIORITY_HIGHEST

 

base+2

内核动态调整一个线程的优先级依赖于该线程是I/O限制还是CPU限制。Win32 API提供了一种使这种调整失效的方法,即通过SetThreadPriorityBoost函数可以设定特定的线程是否可以动态改变其优先级。

在下列5种情况下,Windows2000会提升线程的当前优先级:

1)      I/O操作完成;

2)      信号量或事件等待结束;

3)      前台进程中的线程完成一个等待操作;

4)      由于窗口活动而唤醒图形用户接口线程;

5)      线程处于就绪状态超过一定时间,但没能进入运行状态(处理机饥饿)。

其中,前两条是针对所用线程进行的优先级提升,而后三条是针对某些特殊的线程在正常的优先级提升基础上进行额外的优先级提升。线程优先级提升的目的是改进系统吞吐量、响应时间等整体特征,解决线程调度策略中潜在的不公正性。[1]

下面对这五种情况做一点较详细的详细阐述:

1)      在完成I/O操作后,Windows将临时提升等待该操作线程的优先级,以保证等待I/O操作的线程能有更多的机会立即开始处理得到的结果。为了避免I/O操作导致对某些线程的不公平偏好,在I/O操作完成后唤醒等待线程时将把该线程的时间配额减1。线程优先级的实际提升值是由设备驱动程序决定的。设备驱动程序在完成I/O请求时通过内核函数IoCompleteRequest来指定优先级提升的幅度。提升的量取决于线程所等待的设备;例如,等待键盘的线程会得到较大程度的增加;而等待磁盘的线程会得到中等程度的增加。这种策略能够给予使用鼠标和窗口的交互线程更高的优先级,从而能让I/O为主(I/O bound)线程保证I/O设备一直忙,也能让计算约束线程使用后台的空闲CPU周期。这种策略也为许多分时操作系统如UNIX所使用。[2]

2)      当一个等待执行事件对象或信号量对象的线程完成等待后,它的优先级将提升一个优先级。阻塞于事件或信号量的线程得到的处理机时间比处理机繁忙型线程要少,这种提升可减少这种不平衡带来的影响。SetEvent、PulseEvent或ReleaseSemaphore函数调用可导致事件对象或信号量对象等待的结束。在等待结束时,线程的时间配额被减1,并在提升后的优先级上执行完剩余的时间配额;随后降低1个优先级,运行一个新的时间配额,直到优先级降低到初始的基本优先级。

3)      对于前台进程中的线程,一个内核对象上的等待操作完成时,内核会提升线程的当前优先级。内核在前台应用完成它的等待操作时小幅提升它的优先级,以使它更有可能马上进入运行状态,有效改进前台应用的响应时间特征。用户不能禁止这种优先级提升,甚至是在用户已利用Win32的函数SetThreadPriorityBoost禁止了其他的优先级提升策略时也是如此。

4)      拥有窗口的线程在被窗口活动唤醒(如收到窗口消息)时将得到一个幅度为2的额外优先级提升。窗口系统(Win32k.sys)在调用函数KeSetEvent时实施这种优先级提升,KeSetEvent函数调用设置一个事件,用于唤醒一个图形用户接口线程。这种优先级提升的原因是改进交互应用的响应时间。

5)      系统线程“平衡集管理器(balance set manager)”会每秒钟检查一次就绪队列,是否存在一直在就绪队列中排队超过300个时钟中断间隔的线程。如果找到这样的线程,平衡集管理器将把该线程的优先级提升到15,并分配给它一个长度为正常值两倍的时间配额;当被提升线程用完它的时间配额后,该线程的优先级立即衰减到它原来的基本优先级。如果在该线程结束前出现其他高优先级的就绪线程,该线程会被放回就绪队列,并在就绪队列中超过另外300个时钟中断间隔后再次被提升优先级。平衡集管理器只扫描16个就绪线程。如果就绪队列中有更多的线程,它将记住暂停时的位置,并在下一次开始时从当前位置开始扫描。平衡集管理器在每次扫描时最多提升10个线程的优先级。如果在一次扫描中已提升了10个线程的优先级,平衡集管理器会停止本次扫描,并在下一次开始时从当前位置开始扫描。这种算法并不能解决所有优先级倒置的问题,但它很有效。

 

 



 

[1]陈向群,杨芙清,操作系统教程,北京大学出版社,2001

[2] Abraham Silberschat and Peter Baer Galvin, Operating System Concepts, Addison Wesley, 1998

你可能感兴趣的:(Windows线程优先级提升策略)