linux进程调度程序如何防止进程的饥饿

时间:2016-09-27 12:46:39

标签: linux process linux-kernel operating-system starvation

我已经读过linux内核包含许多调度类,每个调度类都有自己的优先级。要选择要运行的新进程,进程调度程序将从最高优先级类迭代到最低优先级类。如果在类中找到可运行的进程,则选择优先级最高的进程从该类运行。

Robert Love从Linux内核开发中提取:

  

进程计划的主要切入点是功能   schedule(),在kernel / sched.c中定义。这是函数   内核的其余部分用于调用进程调度程序,决定   运行然后运行它的进程。 schedule()是通用的   尊重调度程序类。也就是说,它找到了最高优先级   具有可运行进程的调度程序类,并询问下一步运行什么。   鉴于此,schedule()很简单就不足为奇了   只是功能的重要部分 - 否则也是如此   在这里重现无趣 - 是它调用pick_next_task()   ,也在kernel / sched.c中定义.pick_next_task()函数去了   通过每个调度程序类,从最高优先级开始,和   选择优先级最高的类中的最高优先级进程。

让我们假设以下场景。有些进程在较低优先级的类中等待,并且进程正在连续地添加到更高优先级的类中。低优先级的流程不会饿死吗?

2 个答案:

答案 0 :(得分:1)

它确实会饿死。 有很多方法可以处理这种情况。

  1. 老化,流程在系统中的时间越长,优先级越高。
  2. 调度算法为每个进程提供一个使用CPU的时间量程。时间 - 量子变化,通常,交互过程被给予较低的时间 - 量子,因为它们花费更多时间进行I / O,而耗时/计算过程被给予更大的时间量。 在进程运行其时间量程之后,它将被置于过期队列中,直到系统中没有活动进程。 然后,过期的队列成为活动队列,反之亦然。 这是防止饥饿的两种方法。

答案 1 :(得分:1)

Linux内核实现了基于虚拟时钟的完全公平调度算法。

每个调度实体都有一个sched_entity结构,其快照类似于

struct sched_entity {
    ...
    u64 exec_start;
    u64 sum_exec_runtime;
    u64 vruntime;
    u64 prev_sum_exec_runtime;
    ...
}

以上四个属性用于跟踪进程的运行时,并使用这些属性以及其他方法(update_curr()更新这些属性),实现虚拟时钟。 将进程分配给CPU时,exec_start将更新为当前时间,消耗的CPU时间将记录在sum_exec_runtime中。从CPU sum_exec_runtime取消进程时,prev_sum_exec_runtime中会保留值。 sum_exec_runtime累积计算。 (意思是它单调地增长。)

vruntime存储流程执行期间虚拟时钟已经过的时间量。

如何计算vruntime

忽略所有复杂的计算,计算方法的核心概念是: -

vruntime += delta_exec_weighted;
delta_exec_weighted = delta_exec * (NICE_0_LOAD/load.weight);

此处delta_exec是分配给CPU并从CPU取消的进程之间的时差,而load.weight是依赖于优先级(Nice Value)的进程权重。通常,一个进程的nice值增加1意味着它可以减少10%的CPU时间,从而减轻重量。 处理NICE值为0,权重= 1024 处理以值1重新处理,权重= 1024 / 1.25 = 820(大约)

从上方抽取的点数

  • 当进程获得CPU
  • 时,vruntime会增加
  • 与优先级较低的流程相比,优先级较高的流程vruntime会缓慢增加。

runqueue维护在红黑树中,每个runqueue都有一个与之关联的min_vruntime变量,它在运行队列中的所有进程中保存最小的vruntime。 (min_vruntime只能增加,而不是随着进程的安排而减少。

红黑树中节点的键是process->vruntime - min_vruntime

当调用调度程序时,内核基本上会获取具有最小密钥(最左边的节点)的任务并将其分配给CPU。

较小键的元素将放置在左侧,因此可以更快地安排。

  1. 当进程运行时,其vruntime将稳定增加,因此它最终将在红黑树中向右移动。 由于vruntime对于更重要的流程而言增长速度更慢,因此它们也会向右移动得更慢,因此对于不太重要的流程来说,他们安排的机会更大 - 正如所需的那样。
  2. 如果进程处于休眠状态,则其vruntime将保持不变。因为每个队列min_vruntime会在此期间增加,所以睡眠过程将在唤醒后更多地放在左边,因为密钥(如上所述)变小了。
  3. 因此,如果被剥夺CPU,则没有机会将饥饿作为优先级较低的进程,其vruntime最小,因此密钥最小,因此它会快速移动到树的左侧并因此进行调度。 / p>