Linux线程编程(二)

2 Linux线程调度策略

内核使用调度器来决定下一个CPU时钟周期执行的线程。每个线程都包含一个调度策略及一个静态的调度优先级sched_priority,调度器根据系统上所有的线程的调度策略和静态优先级来决定如何进行调度。
对于使用普通调度策略(SCHED_OTHER, SCHED_IDLE, SCHED_BATCH)的线程来说,sched_priority并不会影响调度结果,且必须设置为0。
对于使用实时策略(SCHED_FIFO,SCHED_RR)的进程,其sched_priority取值为1到99(1为最低值)。实时线程的调度优先级总是高于普通线程。注:POSIX.1的系统在实现中,会要求实时调度策略有32个优先级设置,因此,为了可移植性,可以使用sched_get_priority_min和sched_get_priority_max来查找调度策略所支持的优先级范围。
调度器会为每个sched_priority值维护一个可运行的线程列表。调度器通过查看非空且静态优先级最高的列表,并选择该列表首部的元素作为下一个运行的线程。
线程的调度策略决定了如何根据静态优先级来将一个线程插入到同静态优先级的线程列表(list of runnable threads)中,以及如何在该列表中调整线程的位置。
所有的调度都具有抢占性:如果一个具有更高静态优先级的线程准备运行,当前运行的线程会被抢占并返回到其静态优先级对应的等待列表中。调度策略仅根据具有相同静态优先级的可运行线程列表来决定调度顺序。
进程调度中使用了2个队列:进程一开始会进入ready队列等待调度;当进程执行中遇到I/O阻塞,等待子进程结束或软中断等原因会进入wait队列,等阻塞结束后会返回到ready队列。

2.1 SCHED_FIFO: First in-first out scheduling(实时线程)

SCHED_FIFO仅适用于静态优先级大于0的线程,即当一个SCHED_FIFO的线程变为可运行(runnable)状态时,它会立即抢占所有当前运行的SCHED_OTHER, SCHED_BATCH或SCHED_IDLE 线程。SCHED_FIFO不使用时间片进行调度,所有使用SCHED_FIFO调度策略的线程应该遵守如下规则:

  • 1.当一个运行中的SCHED_FIFO线程被其他有更高优先级的线程抢占后,该线程会返回到其优先级对应的列表的首部,当所有更高优先级的线程阻塞后,该线程将会立即恢复运行;
  • 2.当一个阻塞的SCHED_FIFO 线程变为可运行状态时,该线程会返回到其优先级对应的列表末尾;
  • 3.如果调用 sched_setscheduler(2),sched_setparam(2),sched_setattr(2),pthread_setschedparam(3),pthread_setschedprio(3) (通过pid)修改了正在运行或可运行状态的SCHED_FIFO线程的优先级时,该线程在列表中的位置取决于优先级的变动:
    如果线程优先级增加了,它将会放置到新优先级对应的列表末尾,同时可能抢占正在运行的具有相同优先级的线程;
    如果线程优先级没变,其在运行列表中的位置不变;
    如果线程优先级减小了,它将会放置到新优先级对应的列表的前面。
    根据POSIX.1-2008,通过非 pthread_setschedprio(3)方式来修改线程的优先级,可能会导致其放置到对应优先级列表的末尾。
  • 4.调用了sched_yield(2) (用于释放CPU)的线程将会放置到列表末尾。
    SCHED_FIFO 线程将会一直运行,直到被更高优先级的线程抢占,或调用了sched_yield(2) 。

2.2 SCHED_RR: Round-robin scheduling(轮询调度)

SCHED_RR对SCHED_FIFO做了简单增强。除每个线程仅允许运行在一个最大时间段下外,SCHED_FIFO中的所有规则都适用于SCHED_RR。如果一个SCHED_RR线程已经运行了等于或大于该最大时间段时,该线程会被放置到其优先级列表的末尾。当一个SCHED_RR线程被更高优先级的线程抢占,并在后续恢复运行后,会在先前未过期的时间段下运行。最大时间段可以通过sched_rr_get_interval(2)获得。

2.3 SCHED_DEADLINE: Sporadic task model deadline scheduling

3.14版本之后的Linux提供了一个新的调度策略SCHED_DEADLINE。该策略结合了GEDF(Global Earliest Deadline First)和 CBS (Constant Bandwidth Server)。必须通sched_setattr(2)和sched_getattr(2)来设置和获取该策略。
一个Sporadic task被定义为一系列任务,且每个任务每次仅激活一次。每个任务都有一个relative deadline(该任务应该在该相对时间前停止运行),以及一个computation time(执行该任务需要的CPU时间,对应下图的comp. time)。一个新的任务开始执行时会唤醒(wakeup)一个Sporadic task,该时间点被称为arrival time,start time为一个任务开始执行的时间,absolute deadline(绝对截止时间)为arrival time加上relative deadline的时间点。

在这里插入图片描述

当使用sched_setattr(2)给一个线程设置SCHED_DEADLINE 策略时,可以设置3个参数:Runtime, Dead‐line和Period,对于上面提到的场景来说,通常的做法是将Runtime设置为大于平均计算时间的值(或更坏的场景下,设置为硬实时任务的执行时间);将Deadline设置为对应的dead-line,将Period设置为任务的周期,此时对于SCHED_DEADLINE的调度如下:
Runtime对应上图中的comp.time,Dead-line对应上图的relative deadline

在这里插入图片描述

3个deadline调度参数对应sched_attr结构体中的sched_run‐time, sched_deadline, 和sched_period字段,参见sched_setattr(2)。这些字段的单位为纳秒。如果sched_period的值为0,则它与sched_deadline相同。
内核要求:
在这里插入图片描述

此外,在当前实现中,所有参数的值至少为1024(即,大于1微秒),小于2^63。如果有效性校验失败,sched_setattr(2)返回EINVAL错误。
CBS通过阻止线程超出其运行时间Runtime来保证任务间不互相干扰。
为了确保deadline调度,当SCHED_DEADLINE线程在给定的条件下不可运行时,此时内核必须阻止这些线程的运行。内核必须在设置或修改SCHED_DEADLINE策略和属性时执行准入测试。准入测试用于计算这些修改是否可行,如果不可行,sched_setattr(2)将返回EBUSY错误。
例如,总的CPU利用率应该小于或等于总的可用的CPU。由于每个线程可以在每个Period中最大运行Runtime时间,线程的CPU时间片使用率为Runtime除以Period。
为了满足SCHED_DEADLINE的条件,使用SCHED_DEADLINE策略的线程的优先级是系统中最高的。当一个SCHED_DEADLINE线程运行时,该线程会抢占其他策略下调度的线程。
对SCHED_DEADLINE策略调度的线程调用fork(2)会返回EAGAIN错误(除非该线程设置了reset-on-fork标记)。
当一个SCHED_DEADLINE线程调用了sched_yield(2)将会停止当前任务,并等待新的周期。

2.4 SCHED_OTHER: Default Linux time-sharing scheduling(默认策略)

SCHED_OTHER只能在静态优先级为0时使用(普通线程)。SCHED_OTHER是标准的Linux分时调度策略(不需要实时机制)。
如何从静态优先级为0的列表中选择运行的线程取决于列表中的dynamic优先级。dynamic优先级基于nice值,且在每次线程准备运行时增加。这种机制保证公平处理所有的SCHED_OTHER线程。
在Linux内核源码中,SCHED_OTHER被称为SCHED_NORMAL。

2.5 SCHED_BATCH: Scheduling batch processes

从Linux 2.6.16开始,SCHED_BATCH可以用于静态优先级为0的线程。该策略类似SCHED_OTHER,并根据动态优先级(nice值)进行调度。区别是使用该策略时,调度器会假设线程是CPU密集型的,因此,该调度器会根据线程的唤醒行为施加调度惩罚,因此这种调度策略比较不受欢迎。
该策略比较适用于非交互且不期望降低nice值的负载,以及需要不因为交互而(在负载之间)造成额外抢占的调度策略的负载。
在这里插入图片描述

2.6 The nice value

nice值用于影响CPU调度器对进程的调度偏好。适用于SCHED_OTHER和SCHED_BATCH调度处理。可以通过nice(2),setpriority(2)或sched_setattr(2)修改nice值。
根据POSIX.1,nice值是一个单进程属性,即进程中的所有线程共享一个nice值。然而,在Linux中,nice值是一个单线程属性,相同进程中的不同线程可能使用不同的nice值。
nice值的取值范围根据UNIX系统的不同而不同。在现代Linux系统中,取值为-20(高优先级)到+19(低优先级),而一些系统中的取值为-20…20。在一些非常早期的Linux 内核(Linux 2.0之前)中的取值为-infinity…15。
nice值对相应的SCHED_OTHER 进程的影响根据UNIX系统和Linux内核版本的不同而不同。
2.6.23版本的Linux内核中引入了CFS调度,并采用了一种能根据nice的差值产生更显著影响的算法。在当前的实现下,两个进程的nice差值中,每单位的nice差值对CFS调度的影响因子为1.25 (参见how-is-nice-working,CFS根据虚拟时间进行CPU调度:vruntime = 实际运行时间 * 1024 / 进程权重,可以看到权重大的获得的CPU大,反之获得的CPU小,进程权重为1.25 ^ nice_value)。这种算法使得在有高优先级负载运行的情况下,只能给低nice值(+19)的负载提供很小的CPU;而为高nice值(-20)的负载提供其运行应用需要的绝大部分CPU(如音频应用)。(权重表示是该程序需要的cpu时间的一种表现,如果一个程序需要大量cpu进行处理,可以提高其权重,反之减小其权重。CFS的思想就是让每个调度实体的vruntime互相追赶,而每个调度实体的vruntime增加速度不同,权重越大的增加的越慢,这样就能获得更多的cpu执行时间)
Linux系统可以使用RLIMIT_NICE资源来限制非特权进程的nice值的上限,参见setrlimit(2)。
更多nice值的用法,参见下面的autogroup。

2.7 SCHED_IDLE: Scheduling very low priority jobs

从Linux 2.6.23开始,SCHED_IDLE可以用于静态优先级为0的线程。nice值不会影响该策略。
该策略用于运行非常低优先级的任务(低于nice值为+19的SCHED_OTHER或SCHED_BATCH策略)。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值