进程分为实时进程和普通进程。 实时进程需要立刻执行返回结果,普通进程没有这个需求。
task_struct中有策略信息和优先级信息
1 |
|
对于实时进程,优先级的范围是 0~99;对于普通进程,优先级的范围是 100~139。数值越小,优先级越高。
实时调度策略
对于调度策略,其中 SCHED_FIFO、SCHED_RR、SCHED_DEADLINE 是实时进程的调度策略。
- SCHED_FIFO 就是交了相同钱的,先来先服务,但是有的加钱多,可以分配更高的优先级,也就是说,高优先级的进程可以抢占低优先级的进程,而相同优先级的进程,我们遵循先来先得。
- SCHED_RR 轮流调度算法,采用时间片,相同优先级的任务当用完时间片会被放到队列尾部,以保证公平性,而高优先级的任务也是可以抢占低优先级的任务。
- SCHED_DEADLINE,是按照任务的 deadline 进行调度的。当产生一个调度点的时候,DL 调度器总是选择其 deadline 距离当前时间点最近的那个任务,并调度它执行。
普通调度策略
- SCHED_NORMAL 是普通的进程
- SCHED_BATCH 是后台进程,几乎不需要和前端进行交互。这类项目可以默默执行,不要影响需要交互的进程,可以降低它的优先级。
- SCHED_IDLE 是特别空闲的时候才跑的进程
调度策略的实现者, 调度类
1 |
|
sched_class 有几种实现:
- stop_sched_class 优先级最高的任务会使用这种策略,会中断所有其他线程,且不会被其他任务打断;
- dl_sched_class 就对应上面的 deadline 调度策略;
- rt_sched_class 就对应 RR 算法或者 FIFO 算法的调度策略,具体调度策略由进程的 task_struct->policy 指定;
- fair_sched_class 就是普通进程的调度策略;
- idle_sched_class 就是空闲进程的调度策略。
下面是普通进程的调度
完全公平调度算法 CFS
计算根据进程的优先级分配不同的权重,然后计算每个进程的运行时间值。 对比运行的实际值,小的就优先运行。保证每个进程都可以运行到。
调度队列与调度实体
进程调度实体涉及的成员
1 | struct sched_entity se; |
CFS不同的进程通过把调度的实体挂在红黑树上实现快速的调度。所有可运行的进程通过不断地插入操作最终都存储在以运行时间vruntime为顺序的红黑树中,vruntime 最小的在树的左侧,vruntime 最多的在树的右侧。 CFS 调度策略会选择红黑树最左边的叶子节点作为下一个将获得 CPU 的任务。
每个cpu都有自己的 struct rq 结构,其用于描述在此 CPU 上所运行的所有进程,其包括一个实时进程队列 rt_rq 和一个 CFS 运行队列 cfs_rq。在调度时,调度器首先会先去实时进程队列找是否有实时进程需要运行,如果没有才会去 CFS 运行队列找是否有进程需要运行。
实现不同进程的调度,是通过按优先级从高到低来遍历调度类的方法来实现的。为了确保进程不被饿死,还需要动态更新进程的优先级,保证长时间未运行的进程随着时间变长而提升优先级,使之可以更快的被调用到。rt_sched_class 先被调用,它会在 rt_rq 上找下一个任务,只有找不到的时候,才轮到 fair_sched_class 被调用,它会在 cfs_rq 上找下一个任务。这样保证了实时任务的优先级永远大于普通任务。
行动,才不会被动!
欢迎关注个人公众号 微信 -> 搜索 -> fishmwei,沟通交流。