Linux内核学习笔记——进程调度(二)

4、Linux调度算法

4.1 调度器类

Linux调度器是以模块的方式提供的,这样做的目的是允许不同类型的进程可以有针对性地选择调度算法。这种模块化结构被称为调度器类,它允许多种不同的可动态添加的调度算法并存,调度属于自己范畴的进程。每个调度器都有一个优先级,按照优先级顺序遍历调度类,拥有一个可执行进程的最高优先级的调度器类胜出,去选择下面要执行的那一个程序。
完全公平调度(CFS) 是一个针对普通进程的调度类。CFS采用的方法是对时间片分配方式进行根本性的重新设计:完全摒弃时间片而是分配给进程一个处理器使用比重。通过这种方式,CFS确保了进程调度中能有恒定的公平性,而将切换频率置于不断变动中。

4.2 公平调度

CFS允许每个进程运行一段时间、循环轮转、选择运行最少的进程作为下一个运行进程,而不再采用分配给每个进程时间片的做法。CFS在所有可运行进程总数基础上计算出一个进程应该运行多久,而不是依靠nice值来计算时间片。
每个进程都按其权重在全部可运行进程中所占比例的“时间片”来运行,为了计算准确的时间片,CFS为完美多任务中的无限小调度周期近似设立了一个目标,称作“目标延迟”(即将所有可执行进程调度完一次的周期)。当可运行任务数量趋于无限时,它们各自所获得的处理器使用比和时间片都将趋近于0,将造成不可接受的切换消耗。CFS为此引入每个进程获得的时间片底线,这个底线称为最小粒度,默认情况下是1ms
绝对的nice值不再影响调度决策,只有相对值才会影像处理器时间的分配比例,
共有两个可执行进程,一个进程nice值为0,一个为5,nice值为5的进程的权重将是默认nice进程的1/3,假设目标延时是20ms,那么这两个进程将分别获得15ms和5ms的处理器时间。若两个进程的nice值为10和15,它们分配的时间片比例依旧为3:1,即15ms和5ms。即:绝对的nice值不在影响调度决策,只有相对值才会影响处理器时间的分配比例。
任何进程所获得的处理器时间是由它自己和其他所有可运行进程nice值得相对差值决定的。nice值对时间片的作用不再是算术加权,而是几何加权。

5、Linux调度的实现

5.1 时间记账

5.1.1 调度器实体结构

所有的调度器都必须对进程运行时间做记账。CFS不再有时间片的概念,不能通过每次系统时钟节拍发生时减少时间片的节拍周期的形式。其使用调度器实体结构来追踪进程运行记账。调度器实体结构作为一个名为se的成员变量,嵌入在进程描述符struct tast_struct内。

5.1.2 虚拟实时

vruntime变量存放进程的虚拟运行时间,该运行时间(花在运行上的时间和)的计算是经过了所有可运行进程总数的标准化(或者说时被加权的)。虚拟时间是以ns为单位的,所以vruntime和定时器节拍不再相关。

5.2 进程选择

当CFS需要选择下一个运行进程时,它会挑一个具有最小vruntime的进程。
CFS调度算法的核心:选择具有最小vruntime的任务
CFS使用**红黑树来组织可运行进程队列,并利用其迅速找到最小vruntime值得进程。
①挑选下一个任务
CFS调度器选取待运行的下一个进程,是所有进程中
vruntime最小的那个,它对应的是红黑树中最左侧的叶节点。CFS的进程选择算法可简单地总结为:运行rbtree中最左边叶子结点所代表的的那个进程。实现这一过程的函数是__pick_next_entity()
Tips:虽然在红黑树中查找节点的时间复杂度为 O ( l o g n ) O(logn) O(logn),但更高效和更容易的做法是
把最左侧叶节点缓存起来**。实际上__pick_next_entity()函数并不会遍历树查找最左叶节点,因为该值已经缓存在rb_leftmost字段中。这个函数的返回值便是CFS调度选择的下一个运行进程;如果该函数返回值是NULL,表示没有最左叶子节点,即树中没有任何节点了,此时表示没有可运行的进程,CFS调度器便选择idle任务运行。
②向红黑树中添加进程
进程变为可运行状态(被唤醒),或是通过fork()调用第一次创建进程时,CFS将把进程加入rbtree中。
③从红黑树中删除进程
删除动作发生在进程阻塞(变为不可运行状态)或者终止时。

5.3 调度器入口

进程调度的主要入口:schedule()函数
schedule()是内核其他部分用于调用进程调度器的入口:选择那个进程可以运行,何时将其投入运行。
schedule()通常需要和一个具体的调度类相关联。它会调用pick_next_task(),该函数会以优先级为序,从高到低,依次检查每一个调度类,并且从最高优先级的调度类中,选择最高优先级的进程

5.4 睡眠和唤醒

休眠(被阻塞)的进程处于一个特殊的不可执行状态:进程把自己标记成休眠状态,从可执行红黑树中移出,放入等待队列,然后调用schedule()选择和执行一个其他进程
唤醒的过程刚好相反:进程被设置为可执行状态,然后再从等待队列中移到可执行红黑树中
休眠有两种相关的进程状态:TASK_INTERRUPTIBLE
TASK_UNINTERRUPTIBLE

①休眠
休眠通过等待队列进行处理。等待队列是由某些事件发生的进程组成的简单链表。进程把自己放入等待队列中并设置成不可执行状态。当与等待队列相关的事件发生时,队列上的进程会被唤醒。
如果在京城开始休眠之前条件就已达成,那么循环会退出,进程不会存在错误地进入休眠的倾向
②唤醒
关于休眠有一点需要注意,存在虚假的唤醒。有时候进程被唤醒并不是因为它所等待的条件达成了,因此当进程被唤醒时,会通过额外的一次循环再次检查条件是否为真,以保证它等待的条件真正达成。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值