进程调度

Linux进程分为两种,实时进程和非实时进程(交互式进程、批处理进程)


优先级分为静态优先级和动态优先级,优先级的范围:

调度进程根据动态优先级来决定调度哪个进程,调度程序使用静态优先级评估系统中这个进程与其他普通进程间调度强度

普通优先级有:静态优先级、动态优先级。实时进程还有实时优先级。

静态优先级(static priority):一个用户进程可以通过使用进程的nice值间接改变静态优先级。一个拥有更高静态优先级的进程将会拥有更长的时间片(进程能在处理上运行多长时间)。

Linux支持从19(最低优先级)到-20(最高优先级)的nice值。默认值为0。

内核用100(最高优先级)到139(最低优先级)的整数表示普通进程(非实时进程)的静态优先级 。实时进程优先级为0-99。注意,值越大静态优先级就越低。

对于普通进程而言,动态优先级是基于静态优先级计算出来的。

动态优先级(prio):在 0~MAX_PRIO-1 之间取值(MAX_PRIO 定义为 140),其中 0~MAX_RT_PRIO-1 (MAX_RT_PRIO 定义为100)属于实时进程范围,MAX_RT_PRIO~MX_PRIO-1属于非实时进程。数值越大,表示进程优先级越小。

调度程序通过增加或减少进程静态优先级的值来奖励IO消耗型进程或惩罚cpu消耗型进程。调整后的优先级称为动态优先级。在进程描述符中用prio表示,通常所说的优先级指的是动态优先级。

动态优先级主要用effect_prio()计算,由静态优先级和进程的平均睡眠时间(sleep_avg)决定,随实际任务的实际运行情况得到。而sleep_avg转化为bonus,bonus与sleep_avg成正比。实时进程的优先级在sched_setscheduler()中设置,设定后就不再改变。

普通进程的动态优先级 = max (100, min (静态优先级 - bonus + 5, 139))

bonus(奖赏)是从范围0~10的值,值小于5表示降低动态优先级以惩戒,值大于5表示增加动态优先级以使奖赏。bonus的值依赖于进程的过去情况,与进程的平均睡眠时间有关,也就是说,平均睡眠时间越久,bonus值越大。sleep_avg 反映了调度系统的两个策略:交互式进程优先和分时系统的公平共享。

平均睡眠时间也被调度程序用来评判一个给定进程是交互式进程还是批处理进程的依据 。如果一个进程满足:
动态优先级 ≤ 3 ×  静态优先级/4 + 28    
那么就看做是交互式进程。 高优先级进程比低优先级进程更容易成为交互式进程。例如,具有最高静态优先级(100)的进程,当他的bonus值超过2,即睡眠超过200ms时,就被看做是交互式进程。

交互进程通过平均睡眠时间而被奖励;

实时进程动态优先级prio=MAX_RT_PRIO-1 - rt_priority

实时进程的优先级和它的实时优先级成线性,不随进程的运行而改变。

实时优先级(rt_priority)只对实时进程有意义,取值0~MAX_RT_PRIO-1


调度策略


调度器类


调度器整体框架

本质上, 通用调度器(核心调度器)是一个分配器,与其他两个组件交互:
(1)调度器用于判断接下来运行哪个进程. 
内核支持不同的调度策略(完全公平调度, 实时调度, 在无事可做的时候调度空闲进程,即0号进程也叫swapper进程,idle进程), 调度类使得能够以模块化的方法实现这些策略, 即一个类的代码不需要与其他类的代码交互 
当调度器被调用时, 他会查询调度器类, 得知接下来运行哪个进程
(2)在选中将要运行的进程之后, 必须执行底层的任务切换. 
这需要与CPU的紧密交互. 每个进程刚好属于某一调度类, 各个调度类负责管理所属的进程. 通用调度器自身不涉及进程管理, 其工作都委托给调度器类.

【个人理解】进程调度流程为通用调度器先查询调度器类,判断接下来要调度哪个进程,然后将工作分配给该调度类进行管理进程,调度类调度组件进行底层切换。每个调度器有调度框架和调度器类组成,调度框架识别rq就绪队列,通过查询rq以后再去调动调度器类,每个调度器类中也有自己的进程。每个进程有自己的task_struct。
每个进程都属于某个调度器类(由字段task_struct->sched_class标识), 由调度器类采用进程对应的调度策略调度(由task_struct->policy )进行调度, task_struct也存储了其对应的调度实体标识



【参考】https://blog.csdn.net/gatieme/article/details/51702662

进程调度器的任务就是合理分配CPU时间给运行的进程,创造一种所有进程并行运行的错觉。这就对调度器提出了要求:
1、调度器分配的CPU时间不能太长,否则会导致其他的程序响应延迟,难以保证公平性。
2、调度器分配的时间也不能太短,每次调度会导致上下文切换,这种切换开销很大。

而调度器的任务就是:1、分配时间给进程     2、上下文切换

Linux调度器组成

可以用两种方法来激活调度
一种是直接的, 比如进程打算睡眠或出于其他原因放弃CPU(=主调度器)
另一种是通过周期性的机制, 以固定的频率运行, 不时的检测是否有必要(=周期调度器)
因此当前linux的调度程序由两个调度器组成:主调度器,周期性调度器(两者又统称为通用调度器(generic scheduler)或核心调度器(core scheduler))
并且每个调度器包括两个内容:调度框架(其实质就是两个函数框架)及调度器类


调度器类的就绪队列

调度框架只识别rq(其实它也不能算是运行队列),而对于cfs调度器类它的运行队列则是cfs_rq(内部使用红黑树组织调度实体),实时rt的运行队列则为rt_rq(内部使用优先级bitmap+双向链表组织调度实体), 此外内核对新增的dl实时调度策略也提供了运行队列dl_rq

rq中含有与可运行进程的链表相关的字段。系统中的每个可运行进程属于且只属于一个运行队列。只要可运行进程保持在同一个运行队列中,它就只可能在拥有该运行队列的CPU上执行。

运行队列arrays字段是一个包含两个prio_array_t结构的数组(此数组就有两个值,一个activ一个expired。active字段指向对应于包含活动进程的可运行进程的集合;expired字段指向对应于包含过去进程的可运行进程的集合)。
struct prio_array {
    unsigned int nr_active;//一个集合中所包含的进程数量的计数器
    unsigned long bitmap[BITMAP_SIZE];//优先级位图
    struct list_head queue[MAX_PRIO];//140个双向链表头(因为优先级为0-139,每个链表对应一个可能的进程优先级)
};



【名词解释】时间片:它指定了进程在被抢占之前所能运行的时间。时间片分的过长会导致交互式进程响应不佳。时间片分的过短会导致进程切换带来的消耗。所以:

1、提高交互进程的优先级,同时分配默认的时间片
2、不需要进程一次性用完时间片,可多次使用。

高的优先级可保证交互进程的频繁调用,长的时间片可保证它们可长时间处于可执行状态

平均睡眠时间:平均睡眠时间就是进程在睡眠状态中所消耗的平均纳秒数,这绝对不是对过去时间的求平均值操作.进程在运行的过程中平均睡眠时间递减。最后,平均睡眠时间永远不会大于1s。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值