【操作系统】Linux 进程调度

111 阅读2分钟

Linux 进程调度

Linux 内核中,进程和线程都是用 tark_struct 结构体表示

根据任务的优先级以及响应要求,主要分为两种:

  • 实时任务,对系统的响应时间要求很高,也就是要尽可能快的执行实时任务,优先级在 0~99 范围内的就算实时任务;
  • 普通任务,响应时间没有很高的要求,优先级在 100~139 范围内都是普通任务级别;

调度类

  • Deadline 和 Realtime 调度类:用于实时任务,调度策略有三种:

    • SCHED_DEADLINE:是按照 deadline 进行调度的,距离当前时间点最近的 deadline 的任务会被优先调度;
    • SCHED_FIFO:对于相同优先级的任务,按先来先服务的原则,但是优先级更高的任务,可以抢占低优先级的任务,也就是优先级高的可以「插队」;
    • SCHED_RR:对于相同优先级的任务,轮流着运行,每个任务都有一定的时间片,当用完时间片的任务会被放到队列尾部,以保证相同优先级任务的公平性,但是高优先级的任务依然可以抢占低优先级的任务;
  • Fair 调度类:用于普通任务,由 CFS 调度器管理,两种策略:

    • SCHED_NORMAL:普通任务使用的调度策略;
    • SCHED_BATCH:后台任务的调度策略,不和终端进行交互,因此在不影响其他需要交互的任务,可以适当降低它的优先级。

  • 完全公平调度(Completely Fair Scheduling):分配给每个任务的 CPU 时间是一样

    • 每个任务安排一个虚拟运行时间 vruntime

    • 调度的时候,优先选择 vruntime 少的任务

      • 还要考虑普通任务的权重值:
      • VRunTime+=实际运行时间DeltaExecNICE0LOAD/权重VRunTime+=实际运行时间DeltaExec*NICE0LOAD/权重

CPU 运行队列

Why?

任务远超CPU数量,因此需要排队执行

How?

  • 运行队列(Run Queue, rq):每个 CPU 独有

    • Deadline 运行队列 dl_rq
    • 实时任务运行队列 rt_rq
    • CFS 运行队列 csf_rq :红黑树来描述的,按 vruntime 大小来排序的,最左侧的叶子节点,就是下次会被调度的任务。
  • 优先级

    • Deadline > Realtime > Fair
    • 实时任务总是会比普通任务优先被执行

调整优先级

默认情况下都是普通任务

  • 让某个普通任务有更多的执行时间,可以调整任务的 nice 值(优先级修正数)

    • nice 的值能设置的范围是 -20~19,值越低,表明优先级越高
    • 优先级priority(new) = priority(old) + nice
    • # 启动时指定nice
      nice -n -3 /usr/sbin/mysqld
      # 修改已经运行中的任务的优先级
      renice -10 -p <进程pid>
      #修改调度策略为SCHED_FIFO,并且优先级为1
      $ chrt -f 1 -p 1996
      

Linux 上下文切换

  • CPU 上下文:CPU 运行任务之前必须依赖的依赖环境(寄存器程序计数器
  • CPU 上下文切换:先保存上一个任务的 CPU 上下文,然后将新任务的上下文加载到这些寄存器和程序计数器中,最后跳转到程序计数器。

CPU 上下文切换的类型

  • 进程上下文切换:从一个进程切换到另一个进程

    • 系统调用(用户态与内核态的切换):同一个进程内的上下文切换
  • 线程上下文切换

    • 前后两个线程属于同一个进程:只需要切换线程的私有数据、寄存器等未共享的数据
  • 中断上下文切换

    • 保存进程的当前状态,不需要保存和恢复进程的虚拟内存、全局变量等用户态资源。