正文

线程的调度方案2009-06-13 15:37:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/xman/44352.html

分享到:

时间片(quantum

前面已经提到,时间片就是在Windows检查是否有另外一个同优先级的线程要执行前,线程运行的时间。如果一个线程结束了它的时间片,而又没有另外一个同优先级的线程,Windows重新调度这个线程运行另外一个时间片。每个线程都有一个时间片的数值,它代表了线程可以运行多长时间,直到时间片届满。这个数值不是一个时间的计时长度,而是一个整数,我们称之为时间片单位(quantum units

缺省的情况下,Windows 2000/XP Professional线程运行2个时钟周期(6个时间片单位),Windows Server版线程运行12个时钟周期(36个时间片单位)。每次时钟中断,时钟中断程序从线程时间片中扣除一个固定的值31个时钟周期)。

Windows Server版设置了较长的缺省值是为了减少上下文转换。当有客户请求到来时,服务器应用程序被唤醒后,如果有较长的时间片,它就可以更好的完成这个请求,然后在时间片结束前返回等待状态。

如果线程时间片没有剩余,时间片结束处理进程就会被触发,然后另外一个线程可能被选择执行。当时钟中断发生时,如果系统正处于DPC/Dispatch级别或者更高,例如正在执行一个DPC或者一个中断服务程序,在这种情况下,就算当前的线程在整个时钟中断间隔都没有运行,它的时间片仍然会被减少。如果不是这样做,而设备中断或者DPC又总是刚好发生在时钟间隔中断前,线程的时间片可能因此总不减少。

不同的硬件平台,时钟间隔的长度是不同的。时钟中断的频率是由HAL(硬件层)负责,而不是内核负责。例如,大部分x86单处理器的时钟间隔是10毫秒,大部分x86多处理器的时钟间隔是15毫秒。

每个时钟滴答表示3个时间片单位,而不是一个时间片单位,这种表示方法是为了线程在等待完成的时候,其时间片可以被减少一部分。基本优先级少于14的线程执行了等待的函数,如WaitForSingleObject 或者 WaitForMultipleObjects后,它的时间片就减少1个单位;优先级是14或更高的线程等待后,其时间片会被重新设置。

线程的时间片可以部分被减少的原因是,当线程在时钟间隔计数器激发前进入等待状态,如果没有对其时间片进行调整,那么有可能这个线程的时间片就从不减少。例如:一个线程运行,然后进入等待状态,然后再运行,再进入等待状态。但当时钟间隔计数器激发时,却从来不是当前运行的线程,那么当它运行时其时间片就从不被记账,也就不会减少。

线程的调度方案

线程可以处于的不同的执行状态,图6-14显示了是Windows2000/XP中线程的状态的互相转变。

 

线程的状态有以下几种:

线程状态

说明

Ready(就绪)

此状态下的线程正在等待执行,当调度程序需要找一个线程来执行时,它仅考虑就绪状态下的线程池。

Standby(备用)

已经被选中(当前活动线程的后继),当条件合适时,调度程序对这个线程执行一个上下文转换,备用线程将被切换到某个特定的处理器上运行。对于系统中的每一个处理器,只能有一个线程处于备用状态。

Running(运行)

一旦调度程序将环境切换到某个(备用)线程,这个线程就进入运行状态并开始执行。线程一直执行,直到内核将其抢占去运行一个更高优先级的线程,或者它的时间片到结束运行或自动进入等待状态。

Waiting(等待)

一个线程可能因为以下几个原因而进入等待状态:(1)自动等待一个对象以便同步它的执行。(2)操作系统可以代替该进程进入等待(如为了解决换页I/O)。(3)环境子系统引导线程挂起。

线程等待状态结束后,根据其优先级,开始执行,或者进入就绪状态。

Transition (转变)

当一个线程已经准备好执行,但它的内核栈被换出了内存,这时线程就进入转变状态。一旦它的内核栈被换入内存,线程就进入就绪状态。

Terminated (终止)

当一个线程完成执行,它就进入终止状态。终止后,线程对象可能被删除,也可能不被删除,这将取决于对象管理器什么时候删除对象的策略。如果执行体中有一个指针指向线程对象,执行体可以对线程对象重新初始化并再次使用它。

Initialized (初始)

当一个线程被创建时的状态。(内部使用)

Windows在线程优先级上是以谁将得到CPU”为基准的,但这个方法是实际上如何工作的呢?下面的部分将解释在线程的级别上,由优先级驱动的,抢占式的多任务的调度是如何工作的。注意到Windows在处理线程调度决策上,单处理器系统和多处理器系统是不同的,这将在后续部分解释。

1)自愿切换

线程可能调用Win32的某些阻塞函数如WaitForSingleObject WaitForMultipleObjects来等待某个对象(如事件、信号量、I/O完成的端口、进程、线程、窗口信息等),从而进入等待状态,自动放弃对CPU的占用。该线程进入同优先级就绪队列的末尾,而CPU将上下文切换到就绪队列中的下一个线程并开始执行。

以下就餐的情景能很好的帮助你理解线程的自动切换:在餐厅,你点了一个尚未准备好的汉堡包,为了不阻碍其他的就餐者,你就文明地站到一边,让下一个食客点菜。这时候,你的汉堡包正在准备中。汉堡包准备好之前,你站到了其优先级的就绪队列的尾部。这样似乎有些不公平,因为你先点的,所以当汉堡包准备好了的时候,服务员一般会先给你端过来。

同样在操作系统中,为兼顾公平,大部分线程等待的对象受信后,一般会使用一个临时增强优先级,以让线程可以马上执行。

那么线程剩余的时间片又如何呢?当线程进入等待状态时,时间片的值并不重新设置。实际上,前面已经解释过,当线程的等待状态结束时,它的时间片被减少了1个时间量单位,相当于1/3个时钟间隔。而优先级等于或高于14的线程,等待状态结束后,它们的时间量会被重新设置。

2)抢占式调度

这种调度情况是指一个低优先级的线程被一个较高优先级的线程强抢占。有2个原因会导致这种情况的发生:

l         较高优先级的线程的等待状态结束,也就是另外一个线程在等待的事件发生。

l         线程的优先级被提高或降低。

在上述的任何一个情况下,Windows都必须决定当前运行的线程是否仍然继续运行,还是被一个更高优先级的线程抢占运行。

注意:用户模式下的线程可以抢占内核模式下的线程。其实,线程运行在什么模式下并没有关系。线程的优先级才是决定因素。

当线程被抢占,它被放到了它运行的优先级的就绪队列的头。如果是实时优先级的线程,它的时间量会被重置成一个完整的时间片。如果是动态范围的优先级的线程,它再次运行时,就完成它上次剩余的时间片。

抢占就可以粗略地比喻你的汉堡包已经准备好时,突然总统走来要订一个汉堡包。当总统在拿他的午餐时,并不要求你去队尾,出于一种尊重,你只需站到一边。一旦总统离开,你可以马上获得汉堡包,立即享用。

3)时间片用完

当一个运行的线程使用完它的时间量,Windows必须决定是否要降低线程的优先级,和是否让另外一个线程使用处理器。

如果线程的优先级被降低,Windows寻找一个更适合的线程进行调度。一个更适合的线程是指优先级比当前运行的线程的新的优先级更高的,在就绪队列中的线程。如果线程的优先级没有被降低,而且又有同样优先级的线程在就绪队列中,Windows将在队列中选择下一个线程,而将先前运行的线程放到了队列的尾部,并赋予它一个新的时间片值,将其状态从运行改为就绪。如果没有另外一个同样优先级的线程准备好运行,线程将继续执行它下一个时间片。

4)终止

当线程调用了ExitThread从主函数中返回,或者被TerminateThread杀掉,它都结束运行,运行状态改为终止状态。如果该线程对象没有打开的句柄,就会从进程的线程队列中被删除,其相关的数据结构将会释放并重新被分配。

线程优先级的提升

在五种情况下,Windows会提升线程当前优先级的值:

  • 完成I/O操作时;
  • 等待执行体事件或者信号量受信后;
  • 前台进程的线程完成等待操作后;
  • 因为窗口行为,GUI线程被唤醒时;
  • 当线程准备好运行,但却一直不能运行。(CPU饥饿)

这些调整的目的是为了提高系统整体的吞吐量和响应能力,同时也为了解决潜在的不公平的调度现象。正象任意的调度算法一样,这些调整并不是完美的,并不是所有的应用程序都会从中得到好处。Windows从不提升那些在实时范围内(16-31)的线程的优先级。因此,在谈到实时范围内的线程时,调度通常是可预知的。

本文摘自《Windows Internals》第6章《进程、线程和作业》6.5《线程调度》

阅读(4145) | 评论(0)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

暂无评论
您需要登录后才能评论,请 登录 或者 注册