linux进程调度的基本知识(根据代码自己总结的)

调度的思路

        调度的目的是为了让需要被执行的程序在期望的时间内被执行。而通常调度的方法又可以分为主动调度和被动调度。可以类比下:

        CPU就是一个篮球场,而程序A是广场舞吴大妈,程序B就是篮球狂魔老王,吴大妈想占据篮球场来跳舞,而老王则想占据篮球场来打篮球。显然没办法让他们同时都占据篮球场,因为这样可能会导致受伤,因此老王觉得,好男不跟女斗,就说把篮球场让给吴大妈,这种主动让出篮球场的行为就是主动调度(yield)。吴大妈也不是那种不讲人情世故的人,一看老王都这么大方了,就退一步说,要不我们轮流来用篮球场吧,我用一个小时,你用一个小时,按照这个时间片来轮转,于是就产生了时间片调度的概念,但这个时候有个问题,谁来帮他们统计时间以及通知他们时间已经耗尽了,篮球场管理员老秦就站出来了,充当了调度人员,负责管理篮球场上吴大妈和老王的使用时间,并到时提醒他们。在这种节奏下,吴大妈和老王都在各自的时间片上占据者篮球场,但一旦时间耗尽,就必须立刻换另外一个人使用,这种就是被动调度。

        这天这个篮球场要迎来一场篮球比赛,相对于吴大妈和老王,篮球赛明显比他们的广场舞和篮球训练更重要,因此,这时候如果再让吴大妈和老王轮流使用篮球场,估计篮球场管理员老秦就要下岗了。老秦就找到吴大妈和老王说,现在有个篮球赛,你们就先不要使用篮球场了啊,篮球赛的优先级比你们跳舞和篮球训练的优先级高,等篮球赛结束后,你们再使用篮球场吧,老王和吴大妈也没得办法,只能按照老秦的安排,先让出篮球场,等高优先级的篮球赛结束后再使用吧,这就引入了实时调度器,必须保证高优先级的任务在规定的时间内被执行。篮球赛结束后,吴大妈和老王又在各自的时间片上轮流占据着篮球场。

        这天篮球场上要迎来一个街舞比赛,耗时两周,老秦又去找老王和吴大妈,说让她两休息两周,这把老王和吴大妈不高兴了,两周谁受得了不打篮球不跳舞啊,就跟老秦发牢骚。老秦心想估计这次没办法去说服吴大妈和老王了,就想了个办法,跟吴大妈和老王说:你看街舞比赛相比你们广场舞和篮球训练是不是更重要,现在你们还是轮流使用篮球场,但街舞比赛的优先级要比你们高,所以街舞比赛使用的时间要比你们长,街舞比赛每次使用3小时,你们还是各自1小时,这样轮转执行可以吗?吴大妈和老王一琢磨,既然老秦也让步了,就同意了这个方案。于是基于时间片和优先级的调度策略就诞生了。这既是linux2.6之前的O(1)调度器。

linux调度器

linux调度器是以模块方式提供的,调度器类有

  • dl_sched_class
  • rt_sched_class
  • fair_sched_class
  • idle_sched_class

每个调度器都有相关的调度策略

调度类

描述

调度策略

dl_sched_class

Deadline调度器

SCHED_DEADLINE

rt_sched_class

实时调度器

SCHED_FIFO、SCHED_RR

fair_sched_class

公平调度器

SCHED_NORMAL、SCHED_BATCH

idle_sched_class

空闲任务调度器

SCHED_IDLE

        调度策略是针对每个进程而言的,不是针对系统而言,线程也是一种特殊的进程。也就是说,linux系统中支持多种调度策略的线程,在线程创建时就可以指定线程的调度策略。使用sched_setscheduler()来设置进程(线程)的调度策略。

        系统默认创建的线程的调度策略是SCHED_NORMAL,也就是公平调度类,在此调度策略下,linux内核采用了CFS的调度算法。在其他调度类下,linux内核并不是采用CFS调度策略,这点需要注意。

  • SCHED_FIFO

        先进先出的调度策略,特征是不基于时间片,高优先级抢占低优先级,相同优先级的顺序执行。

  • SCHED_RR

基于时间片的实时调度策略,特征是基于时间片,高优先级抢占低优先级,相同优先级的按照时间片轮转执行。

  • SCHED_NORMAL

绝对公平调度,其实是没办法实现绝对公平,但调度的目标是绝对公平,因此称为绝对公平调度。CFS不直接使用时间片,而是利用处理器的使用比例。其实这个使用比例也是从时间维度上来定义的,并不是从物理上进行分配(CPU只能当作一个整体来使用),就是进程A使用了CPU多长时间,B使用了CPU多长时间。

其实CFS最终还是根据时间来作为调度的依据,但只是不直接使用时间片,而是将时间片经过一次转换,转换为虚拟运行时间(vruntime)。CFS追求的目标就是所有进程的vruntime是相等的。

CFS调度策略

CFS调度策略的目标就是追求所有进程的vruntime是相等的。那这里就有几个问题:

1. vruntime怎么计算?

Vruntime是虚拟运行时间,虽然是虚拟运行时间,但跟真实时间(wall time)也是有关系的,关系就是:

vruntime= NICE_0_LOADWeight *wall time                (公式1)

NICE_0_LOAD就是NICE值为0时的权重,在linux代码中为:1024(32位系统)1048576(64位系统)。

解释下NICE,对于实时调度器,linux内核提供实时优先级来区分不同的进程优先级,对于公平调度器,linux内核提供nice值来表示进程优先级。Nice的值是从-20~19,默认值为0。数值越大,优先级越低。

解释下weight,weight就是根据nice计算得来的,计算公式:

weight = 1024 / 1.25nice                                (公式2)

公式中的1.25取值依据是:进程每降低一个nice值,将多获得10% cpu的时间。公式中以1024权重为基准值计算得来,1024权重对应nice值为0,其权重被称为NICE_0_LOAD。默认情况下,大部分进程的权重基本都是NICE_0_LOAD。

把公式2代入公式1,就可以得到:

vruntime=  NICE_0_LOADWeight *wall time=  102410241.25nice *wall time= 1.25nice*wall time

分析上述公式,可知,在vruntime相同的情况下,nice值越高,优先级越低,其获得的wall time就越少。这跟操作系统的期望是一致的。

2. 什么时候计算vruntime?

Vruntime是由系统定时器周期性调用的,也就是说在定时器中断处理函数中会计算一次vruntime,系统定时器中断的周期是通过CONFIG_HZ来计算的,CONFIG_HZ在内核编译时可设置为200Hz,250HZ,500HZ,100HZ。对应的定时器中断周期就是5ms,4ms,2ms,1ms。

3. vruntime值有什么用?

每次进定时器中断处理函数,计算出的vruntime有什么用?这里需要引入另外一个时间概念,就是分配给进程的时间。

进程的时间 = 总的cpu时间 * 进程的权重/就绪队列所有进程权重之和。

在进程创建时,内核就会为当前进程计算出在一个调度周期内,应该分配给当前进程的运行时间,此运行时间是实际的运行时间,也即是前面的wall time,但注意此处的wall time是个固定值,是在进程创建时就已经计算好了,暂且我们将其重定义为fix wall time。计算vruntime中的wall time是个变量,其随着程序的运行会不断增大。

在定时器中断处理函数中获取wall time,根据公式计算出vruntime,将这个vruntime与就绪进程列表中的其他vruntime进行比较,寻找vruntime最小的进程去运行。注意,在中断处理函数中只是计算下vruntime,并减少当前进程的时间片。如果当前时间片已经耗尽,则将当前进程设置为need_resched,在中断程序返回时会检查need_resched,如果有need_resched,内核则调用schedule()进行进程切换。

此时又有一个疑问,linux内核提供的定时器周期是ms级,如果仅仅通过定时器中断来触发中断,linux系统的响应能力就很差,必然还能有其他途径去触发调度。

Linux 2.6版本后支持用户抢占和内核抢占。以下情况包含了所有可能触发调度的地方。

抢占模式

场景

用户抢占

从系统调用返回用户空间

从中断处理程序返回用户空间

内核抢占

中断处理程序正在执行,且返回内核空间之前

内核代码再一次具有可抢占性的时候

内核中的任务显式调用schedule()

内核中的任务阻塞

也就是说只有在上述情况下,进程间才会进行调度。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值