概念
内核在内存中保存了每个进程的唯一描述,并通过若干接口与其他进程连接起来。调度器的主要目的是为了,在进程之间共享CPU时间,以达到一种程序都在并发执行的假相。
涉及的东西
- 调度策略:内核必须提供一种方法,尽可能公平的为各个进程之间分配CPU时间片,同时又要兼顾不同任务的优先级。
- 上下文切换:调度在各个进程之间切换时,需要保存前一个进程的状态,待下次循环再次执行该进程时恢复其状态,这就是上下文切换。
Linux 中的调度器实现
调度器的一般原理是,按所能分配的计算额能力,尽可能地保证最大的公平性。Linux的调度器一个很好的特性是,它不需要时间片概念(传统的时间片)。所有的可运行进程都按照时间在一个红黑树中排序,所谓时间就是等待时间。等待最长的进程排在最左侧,则下一次调度器会优先考虑让该进程执行。
调度器需要考虑的点
- 进程的不同优先级,更重要的进程必须比次要进程得到更多的CPU时间份额。
- 进程切换不能太频繁,因为上下文切换是有开销的,因减少在进程切换的开销,让CPU的能更多的运用在计算上。
- 两次相邻的任务切换,不能时间过长,否则会积累比较大的不公平值。
调度器的数据结构
有两种方式激活调度。一种是,直接的,比如进程打算睡眠或其他原因;另一种是周期性的,以固定的频率运行,不时的检测是否有必要进行进程切换。
struct task_struct {
...
int prio, static_prio, normal_prio;
unsigned int rt_priority;
struct list_head run_list;
const struct sched_class *sched_class;
struct sched_entity se;
unsigned int policy;
cpumask_t cpus_allowed;
unsigned int time_slice;
...
rt_priority: 表示实时进程的优先级。0~99,值越大优先级越高。
sched_class: 调度器种类
policy: 调度策略。
- SCHED_NORMAL: 普通进程
- SCHED_BATCH/SCHED_IDLE 次要进程,使用完全公平调度器处理。
- SCHED_BATCH 用于非交互的,密集的批处理进程。
- SCHED_RR/SCHED_FIFO 用于实现软实时进程。SCHED_RR 是循环,SCHE_FIFO 是先进先出。
cpu_allowed: 指定进程在哪个CPU上运行
进程处理优先级
- 优先级的内核表示
在用户空间可以使用nice命令设置进程的静态优先级。-20~+19。值越小,优先级越高。 - 计算优先级
动态优先级>普通优先级>静态优先级 - 计算负荷权重
进程每降低一个nice值,则多获得10%的CPU时间。
核心调度器
- 周期性调度器
在系统活动时,内核会按照频率自动调用该调度器对进程进行分配。 - 主调度器
当要将CPU分配给与当前活动不同的另一个进程,会使用主调度器。 - 与fork的交互
会使用父进程的普通优先级作为子进程的动态优先级,内核会确保父进程的优先级的临时提高不会被子进程集成。