Linux内核设计与实现 第4章 进程调度

本文详细探讨了Linux操作系统中的进程调度机制,包括O(1)、CFS等调度算法,进程优先级、时间片概念,以及抢占和上下文切换的工作原理。通过分析,读者将理解如何在响应时间和系统效率间取得平衡。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


进程调度程序可看作是: 可运行态进程之间 分配有限的处理器时间资源 的内核子系统。
在一组处于可运行状态的程序中选择一个来执行,是调度程序的基本工作。
目标是: 在进程响应时间最大系统利用率(吞吐量高) 两个矛盾中寻找平衡。

有如下调度算法:O(1)调度算法 [早期];反转楼梯最后期限调度算法(RSDL),完全公平调度算法(CFS, Completely Fair Scheduler),这俩是一个东西。

策略

进程可以分为I/O消耗性处理器消耗性
I/O消耗性:经常处于可运行状态,运行一会儿等待IO请求阻塞。如键盘输入,网络IO,用户GUI程序(IO密集型)。
处理器消耗性:一直不停运转不需要太多IO需求。调度策略是尽量降低调度频率、延长运行时间。如大量数学运算程序。

不完全是明确的两类,如字处理器,X Windows服务器。

进程优先级

Linux采用两种不同的优先级范围。普通任务nice值实时优先级
nice值:-20~+19,默认为0,值越低优先级越高获得越多处理器时间。
实时优先级:0~99,可配置,值越高优先级越高。
任何实时进程的优先级都高于普通进程,也就是说实时优先级和nice优先级处于互不相交的范畴。
实际上,内核看到的任务优先级和用户看到的并不相同。Linux 内核中使用 0~139 表示任务的优先级,并且,值越小,优先级越高(注意和用户空间的区别)。其中 0~99 保留给实时进程,100~139(映射成 nice 值就是 -20~19)保留给普通进程。

ps -el查看NI列为进程对应nice值。
在这里插入图片描述
查看进程的实时优先级,实时进程在RTPRIO列显示优先级,ps -eo state,uid,pid,ppid,rtprio,time,comm 则不是实时进程。
在这里插入图片描述

时间片(timeslice)

时间片是一个数值,表示进程再被抢占前所能持续运行的时间。太长导致系统对交互的相应欠佳,太短导致系统进程切换带来大量处理器消耗。
Linux并没有直接分配时间片到进程,它是将处理器的使用比分给进程,也就是进程分的实际时间片跟系统负载密切相关。很多其他操作系统的默认时间片为10ms。

Linux调度算法

linux调度器是以模块的方式提供,目地是对于不同类型的进程可以有针对性的选择调度算法。该模块化结构被称为调度器类(scheduler classes)。
CFS是针对普通进程的调度类。获得的最小时间片称 最小粒度默认是1ms,不是算数加权是几何加权,分配得到的时间片不再是跟nice的绝对值直接相关,而是相对值处理器使用比。

Linux调度实现

包括了四个组成部分:

  1. 时间记账(Time Accounting)
  2. 进程选择(Process Selection)
  3. 调度器入口(The Scheduler Entry Point)
  4. 睡眠和唤醒(Sleeping and Waking Up)

1. 时间记账

在include\linux\sched.h中定义,调度器实体struct sched_entity,成员vruntime记录程序运行了多长时间还应该运行多长时间ns。update_curr()计算当前进程执行时间,由系统定时器周期调用。
update_curr()

2. 进程选择

CFS调度算法的核心是 选择具有最小vruntime的任务。
CFS采用红黑树来组织可运行的进程队列,节点键值是vruntime。
选择下一个要运行的任务:就是红黑树最左边叶子节点所代表的那个进程。若返回NULL则表示没有可运行的节点,CFS便选择idle任务运行。__pick_next_entity()
加入进程到树:进程变为可运行状态fork()。enqueue_entity()
删除进程从树中:dequeue_entity()

3. 调度器入口

统一的调度器入口schedule(),通常和一个具体的调度器类相关联,在kernel/sched/core.c中定义。找到一个最高优先级的调度类,调度类有自己的运行队列,知道谁是下一个该运行的进程。
pick_next_task()按优先级检查每一个调度类,选择高优先级进程。每个调度类也自己实现了pick_next_task()。
schedule()
 pick_next_task()
    class->pick_next_task()
      pick_next_entity()
        __pick_next_entity()

4. 睡眠和唤醒

休眠(被阻塞。INT、UNINT)的进程处于一个特殊的不可执行状态。为等待某一事件进入休眠。
内核干的事:进程把自己标记称休眠,从可执行红黑树中移除,放入等待队列;任何调用schedule()选择和执行一个其他进程。
唤醒: 过程刚好相反,进程被设置为可执行状态,然后从等待队列中移入可执行红黑树中。
等待队列: 由 等待某些事件的进程组成 的简单链表。TASK_INTERRUPTIBLE和TASK_UNINTERRUPTIBLE位于同一等待队列,等待事件不能运行。不同的是TASK_UNINTERRUPTIBLE的进程会忽略信号。
伪唤醒: (被唤醒不是因为等待的事件发生了)。进程状态被设置为TASK_INTERRUPTIBLE,则信号可以唤醒线程,因此进程检查并处理信号。

抢占和上下文切换

上下文切换: 从一个可执行进程切换到另一个可执行进程。由context_switch()函数负责处理,当一个进程被选为下一个运行的对象时,schedule()就会调用该函数。
context_switch()函数中主要调用两个函数,

  1. switch_mm()切换虚拟内存,
  2. switch_to()切换处理器状态,包括了栈信息、寄存器信息、与体系结构相关的状态信息。

schedule()
  context_switch()
    switch_mm()
    switch_to()

need_resched标志

内核提供need_resched标志 表明是否需要重新执行一次调度。
每个进程都包含need_resched标志,当某个进程应该被抢占或者优先级高的进程进入可执行状态时,这个标志将被设置。内核会检查该标志确认被设置 并调用schedule()切换到新进程。
位置: need_resched标志在thread_info结构体里,在某个标志变量的某个位里边。
访问和操作: 用于访问和操作need_resched标志的函数有三个:

  1. set_tsk_need_reshed()
  2. clear_tsk_need_reshed()
  3. need_resched() // 检查标志值并返回真假

用户抢占

内核无论是在 中断处理程序 还是 在系统调用后 返回,都会检查need_resched标志,如果need_resched标志被设置会导致schedule()被调用,此时发生用户抢占。
中断处理程序或系统调用返回的路径跟具体的体系结构有关,在entry.S中实现。
用户抢占在以下情况产生:

  1. 从系统调用返回用户空间时。
  2. 从中断处理程序返回用户空间时。

内核抢占

其他大部分操作系统,调度程序无法在 内核级的任务正在执行时 重新调度,不具备抢占性。
对于Linux来说,只要重新调度是安全的(没有持有锁,锁是非抢占区域的标志),内核可以在任何时间抢占正在执行的任务。
每个进程的thread_info有preempt_count计数器,使用锁时加1,释放锁时减1。
内核抢占在以下情况产生:

  1. 中断处理程序正在执行,且返回内核空间之前。
  2. 内核代码再一次具有可抢占性时。
  3. 内核任务显示调用schedule()。
  4. 内核任务被阻塞,同样也会导致调用schedule()。

实时调度策略

SCHED_NORMAL, SCHED_BATCH 和 SCHED_IDLE 进程会映射到 fair_sched_class (由 CFS 实现);SCHED_RR 和 SCHED_FIFO 则映射的 rt_sched_class (实时调度器)。

实时任务的优先级是静态的。

SCHED_FIFO,简单先入先出,无时间片,一直执行直道被阻塞或显示释放处理器,同优先级则轮流执行(也就是当一个任务完成后,会被放到队列尾部等待下次执行),只有更高优先级的FIFO或者RR才能抢占。
SCHED_RR,实时轮流调度算法,带有时间片的SCHED_FIFO。默认的时间片是 100ms。

硬实时任务:会有严格的时间限制,任务必须在时限内完成。比如直升机的飞控系统。然而,Linux 本身并不支持硬实时任务,但是有一些基于它修改的版本,如 RTLinux(它们通常被称为 RTOS)则是支持硬实时调度的。
软实时任务:软实时任务其实也会有时间限制,但不是那么严格。也就是说,任务晚一点运行任务,并不会造成不可挽回的灾难性事故。例如,VOIP 软件会使用软实时保障的协议传来送音视频信号,但是即便因为操作系统负载过高,而产生一点延迟,也不会造成很大影响。
无论如何,软实时任务总会比普通任务的优先级更高。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值