进程调度
进程调度的核心代码实现参考 kernel/sched/ 目录文件,主要包含以下几个部分:
- 调度算法:Linux 中实现了多种不同的进程调度算法,如 CFS(Completely Fair Scheduler)、O(1) 调度算法、实时调度算法等,并且各个算法之间可以配置和切换,由用户指定默认调度器。
- 调度队列:调度算法的 实现需要用到调度队列,它通过双向链表的数据结构来管理所有进程。Linux 中有就绪队列、休眠队列、实时队列等不同类型的队列,它们存储着不同状态的进程。
- 进程状态:Linux 中的进程状态有很多种,如 TASK_RUNNING(运行中)、TASK_INTERRUPTIBLE(可中断的)、TASK_UNINTERRUPTIBLE(不可中断的)、TASK_STOPPED(已停止的)等。进程在不同状态下会被放置到不同类型的调度队列中,以便进行合适的调度。
调度策略
内核中定义了上面这几个宏,代表不同的调度策略。在linux中调度器是模块式的,允许不同的进程自由选择调度算法
进程优先级
内核中处理优先级如上所示,范围是0-139,数值越低,优先级越高,其中nice映射到100-139,RT优先级逆向映射到0-99。所以这也是为什么RT进程优先级总是高于NORMAL进程。
运行队列
struct rq {
raw_spinlock_t __lock;
unsigned int nr_running;
struct cfs_rq cfs;
struct rt_rq rt;
struct dl_rq dl;
struct task_struct __rcu *curr;
struct task_struct *idle;
struct task_struct *stop;
int cpu;
int online;
}
内核定义了一个per-CPU变量runqueues,其类型是struct rq。所有的就绪进程都会被放入某个CPU的rq上去,具体放到哪个rq上,这个在调度均衡里面讲。内核一共定义了五个调度类,属于不同调度类的进程会被放入不同的子队列,所以rq中包含三个子运行队列cfs_rq、rt_rq、dl_rq。为啥只有3个子运行队列呢?因为有两个调度类idle、stop,每个CPU只能有一个进程,所以没必要弄个队列,直接关联它们的进程就可以了