• 6.进程调度 20100102 15:16 150人阅读 评论(0) 收藏


     Linux进程调度基于分时(time sharing),分时依赖于定时中断。调度的依据是优先级(回忆140个双向链表)。传统上,进程可以分为"I/O型"与“CPU型”;按另一种分法可分为:1.交互式进程;2.批处理进程(编译器、科学计算、数据库搜索引擎);3.实时进程(音频、视频)。以上分类一定程序上相互独立,一个批处理进程可能是I/O型,也可能是CPU型。如数据库服务器是I/O型、图像绘制程序是CPU型。Linux调度器可明确认出实时进程。

    虽然内核可否抢占在编译内核时确定,但Linux进程是抢占式的。而“分时系统”也是基于时间片到的时候,设置thread_info中的TIF_NEED_RESCHED,让时钟中断返回用户程序时启用调度程序,“抢占”当前进程。当进程进入TASK_RUNNING态,内核查它的动态优先级是否大于当前进程。是,则current执行被中断。要注意的是,被抢占的进程仍处于TASK_RUNNING态。系统中至少有一个进程在执行,就是进程0。每个进程有三种调度类型:1.SCHED_FIFO先进先出实时调度;2.SCHED_RR分时实时调度;3.SCHED_NORMAL。它们作为进程描述符的成员存储。
    每个进程首先有个静态优先级。内核用100-139这40个数来标记。越小,优先级越高。新进程继承父进程的优先级。静态优先级的作用是决定进程的基本时间片。若1.小于120,则基本时间片为(140-它)*20;2.>=120,则为(140-它)*5。即静态优先级高,则获CPU时间片长。此外,还有动态优先级。范围从100-139。它表示调度程序选择要执行的进程时的度量。经验上,它=(静态优先级-(bonus-5))。bonus为0-10。表示对动态优先级的奖赏或惩罚,它与“平均睡眠时间”有关。静、动态优先级以及后面的实时优先级也是进程描述符的成员。
    设想,某个运行时间需很长的高优先级进程一次时间片用完后,即使算上bonus,它优先级仍可能最高。调度程序再次选中它,这使其它稍低优先级的进程得不到CPU,造成饥饿。为避免此情况,对可运行进程(注意,是可运行进程)维护两个不相交的集合,它们是活动进程与过期进程。只有在活动进程集合中的可运行进程才可被调度程序选中,且一次时间片用完,则放入过期进程中,直到活动进程集合为空。为空时,交换两个集合,继续按优先级进行调度。但为获得较好的用户体验,必须提高交互式进程的性能,所以调度程序在用完一个交互式进程的时间片时,仍将其放入活动进程集合,除非以下情况:1.最先进入过期进程集合的进程已经等待过长的时间(一般是1000节拍乘以可运行进程数+1);2.过期进程静态优先级比当前的交互式进程高。这时,就将交互式进程移入过期进程集合。这样,最终也会让活动进程集合为空,达到设想的状态。例外的情况是实时进程。每个实时进程与一个实时优先级相关(1-99),实时的表现在于,实时进程运行过程中, 不会让低优先级的进程得到运行机会。如前,每个优先级的进程在同一个链表中,当为SCHED_FIFO时,调度程序选中最高优先级的链表队首的实时进程运行前,会仍将它放在链表头,时间片用完时,定时中断返回用户态时会再启动调度程序,如果此时没有更高优先级的实时进程可运行,那么还会从该链表头选中同一进程,并还将它放在表头,再运行它。这就是FIFO。但当它是SCHED_RR调度类型时,被调度程序选中执行前,会将它放到链表尾。时间片到后,会选中新队头进程。无论是哪种情况,调度程序都不会选中比它们低优先级的进程。实现上,就是不像普通进程那样设两个集合,而只有一个集合。
    上述活动进程、过期进程集合是与CPU时刻相关的数据结构,它们应存在何处?存在“可运行进程队列”中,它存在“每CPU变量”(per-CPU variable)中,它们在主存中经过精心排列,以对应到高速缓存的不同行。"可运行进程队列"是个结构体,结构中有此集合中进程数量的计数器以及优先级位图,它最重要的成员即是活动进程、过期进程两个集合,每集合有0-139个链表头,指向本集合优先级的可运行进程的描述符指针。另外有active和expire指针指向每个集合。如前所述,当需要时,只要交换这两个指针即可,结构中还有一个指向当前运行进程的描述符指针。
    分时,优先级由时间片实现,时间片在哪里?它也在进程描述符中,可运行进程初次被选中时,会根据静态优先级初始化它描述符中的时间片字段。每次定时中断,将描述符中剩余时间片数量减去中断间隔时间,若非0,继续运行,若0,则先按静态优先级设置基本时间片,再设置进程描述符的thread_info->flags为TIF_NEED_RESCHED,使本次中断返回用户程序时调用调度程序,最后改变活动进程链表。一个细节问题是,当一个父进程创建子进程时,子进程的剩余时间片应该设为多少?应当将父进程的剩余时间片一分为二,父子平分。以避免一个进程通过不断创建子进程来霸占CPU。为配合“活动进程过期进程”方案。进程描述符中也应该存有进程最近一次被调度的时间,这通常由64位寄存器tsc赋值。这是可运行进程之间的调度。
    调度程序本身由schedule()函数实现。它在以下情况被调用:1.current进程不能获取资源而阻塞。此时会把current插入适当的等待队列,将TASK_RUNNING改为TASK_INTERRUPTIBLE或TASK_UNINTERRUPTIBLE。再调用schedule(),schedule会将当前不处于RUNNING的进程从可运行队列中删除,关键是schedule()调用完成之后,会检查资源是否可用,不可用则会再调schedule。猜测,等待资源时,会将参数存于某处,资源到,中断来,会按参数唤醒等待进程。否则永远不可执行。schedule()函数关键是设next指向下个要运行进程。并用switch_to来实现相应的上下文更替。schedule先禁用内核抢占、完成当前进程的队列交换处理。若next是内核线程,它仍用pre的地址空间(后面会说),否则,context_switch完成,并完成地址空间的变换,并switch_to()。之后,因为上下文已换,schedule()的剩余指令并不由新进程执行,而由prev的prev执行,以再给它一次被CPU选中的机会。

    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    Note/Solution 转置原理 & 多点求值
    Note/Solution 「洛谷 P5158」「模板」多项式快速插值
    Solution 「CTS 2019」「洛谷 P5404」氪金手游
    Solution 「CEOI 2017」「洛谷 P4654」Mousetrap
    Solution Set Border Theory
    Solution Set Stirling 数相关杂题
    Solution 「CEOI 2006」「洛谷 P5974」ANTENNA
    Solution 「ZJOI 2013」「洛谷 P3337」防守战线
    Solution 「CF 923E」Perpetual Subtraction
    KVM虚拟化
  • 原文地址:https://www.cnblogs.com/qqmomery/p/4700466.html
Copyright © 2020-2023  润新知