调度

系统调度器通过判断哪个竞争线程得到下一个处理器时间分片来控制多任务。调度器使用调度优先级来决定下一个执行的线程是哪个

调度优先级

线程基于它们的调度优先级来被调度运行,每个线程都有一个绑定的调度优先级。0~31(最高)。仅仅zero-page线程可以有0 优先级。(zero-page 线程,是当系统中没有其它的线程需要执行的时候,操作系统用来把空闲的页面设置为0的)

系统将具有相同优先级的所有线程视为相等。系统以循环方式将时间片分配给具有最高优先级的所有线程。如果所有这些线程都还没准备好执行,系统以同样的方式循环下一个优先级的所有的线程,以此类推。如果一个更高优先级的线程准备好执行了,系统停止运行低优先级的线程(不允许它执行完自己的时间片),并给高优先级的线程一个完整的时间片。

线程的优先级由下面的标准决定

1. 进程优先级类(priority class)

2. 线程在它的进程的优先级类中的优先等级(priority level)

优先级类和优先级等级,形成了线程的基本优先级。

优先级类(priority Class)

每个进程,属于下面的进程优先级类中的一个:

IDLE_PRIORITY_CLASS
BELOW_NORMAL_PRIORITY_CLASS
NORMAL_PRIORITY_CLASS
ABOVE_NORMAL_PRIORITY_CLASS
HIGH_PRIORITY_CLASS
REALTIME_PRIORITY_CLASS

默认,NORMAL_PRIORITY_CLASS 类。使用CreateProcess函数在创建子进程的时候指定它的优先级类。如果CreateProcess的调用者的优先类为IDLE_PRIORITY_CLASS 或 BELOW_NORNAL_PRIORITY_CLASS,子进程将继承它。使用GetPriorityClass来判断当前进程的优先级类,使用 SetPriorityClass 函数改变进程的优先类。

监控系统的进程,比如屏幕保护程序,或者定期更新显式的application 应该使用IDLE_PRIORITY_CLASS。这将阻止这个进程的线程,它肯定没有高的优先级,打断更高优先级的线程的执行。

使用HIGH_PRIORITY_CLASS 的时候应该小心。如果一个线程以最高的优先级执行了很长的一段时间,系统中其它线程将无法得到处理器时间。如果几个线程被设置了这样的优先级,线程就失去了它们的高效性。高优先级类应该保留给那些必须响应时间敏感的事件的线程。如果你的application 执行一些需要高优先级类的任务,但剩下的时间将执行一些低优先级的任务。使用SetPriorityClass 来暂时提高其优先级,然后再在不需要的时候将其优先级降低。另一个策略是,创建一个高优先级的进程,它所有的线程,大部分时间都是阻塞的,只有当关键的任务出现了,才唤醒其中的线程。重要的点是:高优先级线程应该执行一段时间,仅仅当它有了时间敏感的任务要执行的时候才会执行。

永远都不要使用REALTIME_PRIORITY_CLASS ,这将中断管理鼠标输入,键盘输入和备份磁盘刷新的系统线程。这个类适用于那些直接与硬件交互的线程,或者执行一些简短的、需要控制中断次数的任务的线程。

优先级别(priority Level)

同样,有下面几类:

THREAD_PRIORITY_IDLE
THREAD_PRIORITY_LOWEST
THREAD_PRIORITY_BELOW_NORMAL
THREAD_PRIORITY_NORMAL
THREAD_PRIORITY_ABOVE_NORMAL
THREAD_PRIORITY_HIGHEST
THREAD_PRIORITY_TIME_CRITICAL

线程创建的时候,使用的默认都是THREAD_PRIORITY_NORMAL。这意味着,线程优先级和进程优先级是一样的。创建线程后,可以使用SetThreadPriority  函数来调整该线程相对于进程中的其它线程的优先级。

典型的场景就是:使用THREAD_PRIORITY_ABOVE_NORMAL 或 THREAD_PRIORITY_HIGHEST 来设置进程的输入线程,确保application 及时的给用户响应。后台线程,尤其是处理器密集型的后台线程,可以设置为THREAD_PRIORITY_BELOW_NORMAL 或 THREAD_PRIORITY_LOWEST,以确保在必要的时候可以抢占它们。但是,如果你有一个线程,在等待低优先级的线程完成一个任务,应该确认,将阻塞正在等待的高优先级的线程的执行。为了这样做,可以使用 wait functioncritical section, or the Sleepfunction, SleepEx, or SwitchToThread 。这比线程执行循环更可取。否则,进程可能会死锁,因为永远都不会调度具有较低优先级的线程。

使用 GetThreadPriority 可以得到线程当前的 优先级。

基础优先级

基础优先级,由进程优先级类,以及线程优先级别组成。

如下表:

 THREAD_PRIORITY_IDLELOWESTBELOW_NORMALNORMALABOVE_NORMALHIGHESTTIME_CRITICAL
IDLE_PRIORITY_CLASS12345615
BELOW_NORMAL_PRIORITY_CLASS14567815
NORMAL_PRIORITY_CLASS167891015
ABOVE_NORMAL_PRIORITY_CLASS18910111215
HIGH_PRIORITY_CLASS1111213141515
REALTIME_PRIORITY_CLASS16222324252631

上下文切换(Context Switches)

调度管理器给每个优先级都维护了一个可执行的线程的队列。被称为ready thread(就绪线程)。当一个处理器空闲,系统执行一个context switch。步骤如下:

1. 保存刚刚结束了执行的线程的context

2. 将刚结束执行的线程放到它的优先级对应的队列的队尾

3. 找到最高优先级的包含就绪线程的线程队列

4. 将队列的头部的线程取出,加载它的context,执行它。

下面的类型的thread 不是就绪线程

1. 以CREATE_SUSPENDED 标志创建的线程

2. 在执行的时候,通过SuspendThread 或 SwitchToThread 函数暂停执行的线程

3. 等待同步对象或输入的线程

直到被阻塞或被暂停的线程准备好执行了,调度器不会给它们申请任何的处理器时间分片,这和优先级无关。

最常见的context switch 的场景是:

1. 时间片用完

2. 有一个更高优先级的线程准备好执行了

3. 一个正在执行的线程开始了等待操作。

当一个线程需要等待,它放弃了时间片的剩下的部分。

优先级提升

每一个线程都有一个动态优先级。这是调度器用来判断执行哪个线程的依据。初始,一个线程的动态优先级就是它的基本优先级。系统可以提升和降低动态优先级,确保线程是响应的,没有线程是处理器时间饥渴的。系统不提升,基本优先级在16~31 的线程的动态优先级。

系统提升线程的动态优先级以增强其响应性,如下:

1. 当一个使用NORMAL_PRIORITY_CLASS 的进程被设置为foreground,调度器提升foreground 窗口绑定的进程的优先级类,由此,它>=任何background process 的优先级类。这钟改变持续到foreground 窗口不再是foreground。

2. 当一个窗口接收到输入,比如,定时消息,鼠标消息,或键盘输入,调度器,提升拥有该窗口的线程的优先级

3. 阻塞线程的等待条件被满足了,调度器,提升该线程的优先级。

可以通过SetProcessPriorityBoost or SetThreadPriorityBoost  禁止优先级提升功能。GetProcessPriorityBoost or GetThreadPriorityBoost 函数可查看是否已经被禁止。

当提升了线程的动态优先级,调度器在每次该线程执行完了一个时间片后,将其优先级降低一个等级,直到线程调回了其原来的优先级。一个线程的动态优先级永远不会低于它的基本优先级。

优先级倒置

当两个或多个不同优先级的线程,在竞争着去被调度,产生优先级倒置。想象如下情景:三个线程,T1,T2,T3.T1 高优先级,准备好了被调度。T2,低优先级,正在一个critical section执行。T1,一个高优先级的线程,从T2 等待一个共享资源。T3 是中优先级,T3 得到了大部分的处理器时间,因为T1 在从低优先级的T2 等待共享资源,T2 不会离开critical section,因为它没有更高的优先级,它 不会被调度。

调度器,通过随机的提升ready 线程的优先级来解决这个问题(在这种情况下,低优先级的锁拥有者)。T2 执行足够的时间,以至于能离开critical section,之后,T1 才能进入critical section。如果T2 没有足够的CPU 事件来退出critical section,它将在下一个调度周期有机会得到调度机会。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值