Linux进程调度入门


基础知识

思维导图

调度类和调度策略

摘自:https://zhuanlan.zhihu.com/p/554149581

  • Stop调度器,stop_sched_class:优先级最高的调度类,可以抢占其他所有的进程,但不能被其他进程抢占。用于执行一些特别紧急的进程。由于每个cpu只有一个stop线程(migration/N),所以就没有具体的调度策略及优先级,内核提供了一些接口可以向这些进程push work。主要用于负载均衡机制中的进程迁移、softlockup检测、cpu hotplug、RCU等。

  • Deadline调度器,dl_sched_class:使用红黑树,把进程按照绝对截止期限进行排序,选择最小进程进行调度运行,属于硬实时,是用于对调度时间有明确要求的进程。由于该调度类用的是进程设置的三个调度参数(运行周期、运行时间、截止时间)作为调度依据,用不到优先级,不过为了跟其他调度类有优先级划分,该类调度器的进程优先级被设为-1。用于调度有严格时间要求的实时进程,如视频编解码等。常见的调度策略是:

    • SCHED_DEADLINE:限期进程调度策略,使task选择Deadline调度器来调度运行。
  • RT调度器,rt_sched_class:实时调度器,为每个优先级维护一个队列,属于软实时,适用于只要可运行就希望立马能运行的进程。优先级为0~99,数字越大优先级越高。实时调度类分为两个调度策略:

    • SCHED_RR:时间片轮转,进程用完时间片后加入优先级对应运行队列的尾部,把CPU让给同优先级的其他进程。
      • SCHED_FIFO:先进先出调度没有时间片,没有更高优先级的情况下,只能等待主动让出CPU。
  • CFS调度器,cfs_sched_class,完全公平调度器,采用完全公平调度算法,引入虚拟运行时间概念。给广大普通线程使用。优先级为100~139。该调度类包含三个调度策略:

    • SCHED_NORMAL:使进程选择CFS调度器来调度运行
      • SCHED_BATCH:批量处理,希望减少调度次数,每次调度能执行的时间长点。
      • SCHED_IDLE:优先级特别低的进程,能分到的cpu时间比例很低,但也是总能分到。
  • IDLE调度器,idle_sched_class:空闲调度器,每个CPU都会有一个idle线程,当没有其他进程可以调度时,调度运行idle线程。在内核启动的时候就创建了每cpu的idle进程,属于最低优先级的进程。

在task_struct中有4个字段表示优先级:

  • Rt_priority:用来记录实时进程的用户空间的静态优先级。
  • Static_prio:用来记录CFS进程的用户空间的动态优先级并做了转换(nice+120),在进程启动时分配,用户可以通过nice()或sched_setscheduler()更改。
  • Normal_prio:规范优先级,在创建进程时会继承父进程的normal_prio。为了将RT进程和CFS进程的优先级统一在一个数轴上,实时进程的转换:normao_prio = 99 – rt,普通进程的转换:normal_prio = static_prio。
  • Prio:动态优先级,是调度类考虑的优先级,有些时候会暂替提高该优先级,比如实时互斥锁。一般等于normal_prio,对进程所有的处理都以动态优先级为准。

数据结构

摘自:https://zhuanlan.zhihu.com/p/554149581

对于每个CPU只能有一个stop和idle,因此不需要队列;

每一个CPU都会有一个per-cpu变量struct rq,每个struct rq上又会有三个不同调度类的调度队列,然后调度队列要用不同的数据结构(比如红黑树)来管理每一个进程的调度实体(sched_entity),进程的task结构体中也会有指针指向它自己的调度实体。

调度过程

摘自:https://zhuanlan.zhihu.com/p/554149581

还是经典的状态转换图:

无论是新建的进程,还是阻塞的进程,想要进入到运行队列,都是靠唤醒来实现的,只不过两种唤醒有所不同。🤔

关于调度时机,文章是这样介绍的🤔:

我们跟着看被动调度:😊

时钟中断

唤醒阻塞进程的时候

创建新进程的时候

设置进程优先级的时候

负载均衡时

这里对触发调度和执行调度做一个简单的理解,以时钟中断为例,时钟中断只是触发调度,此时检查进程的时间片有没有用完,如果没有用完是不会切换进程的🤔(只是简单的理解举例)

再理解一下唤醒:(纯个人瞎猜😂)

如果是创建新的进程,那么就顺着走,创建完了新的进程就会调用唤醒相关的函数,然后决定调度;

如果是阻塞唤醒,笔者猜想是否相应的事件会产生中断来通知内核?🤔这样就会触发调度来决定被唤醒的进程被调度到哪里?🤔

对于设置进程的优先级,会通过nice主动进入到内核,然后调用到相关调度的内核模块:

负载均衡又是什么道理呢?🤔

参考这个https://zhuanlan.zhihu.com/p/662916716

似乎负载均衡也要靠时钟中断来维持捏🤔

如何设置进程的优先级

参考这篇文章:https://docs.pingcode.com/baike/1019204

#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/resource.h>
int main() {
int priority = 10;
pid_t pid = getpid();
if (setpriority(PRIO_PROCESS, pid, priority) < 0) {
perror("setpriority");
return 1;
}
printf("Process priority set to %d.n", priority);
return 0;
}

参考

https://zhuanlan.zhihu.com/p/554149581

https://zhuanlan.zhihu.com/p/662916716

https://docs.pingcode.com/baike/1019204


文章作者: q1ming
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 q1ming !
  目录