Linux调度与进程/线程的创建
2021-04-20 18:28
- 在Linux里面,进程可以分成两种:一种为实时进程,需要尽快执行返回结果;另一种是普通进程。
-
在task_struct中,有一个成员变量叫调度策略。优先级配合调度策略,优先级就是一个数值,对于实时进程,优先级的范围是0~99;对于普通进程,优先级的范围是100~139。数值越小,优先级越高。
-
对于实时进程调度策略SCHED_FIFO、SCHED_RR、SCHED_DEADLINE:
SCHED_FIFO:高优先级的进程可以抢占低优先级的进程,而相同优先级的进程,遵循先来先得。
SCHED_RR:轮流调度,采用时间片,相同优先级的任务当用完时间片会被放到队列尾部,以保证公平性,而高优先级的任务也是可以抢占低优先级的任务。
SCHED_DEADLINE:按照任务的deadline进行调度,当产生一个调度点时,调度器总是选择其deadline距离当前时间点最近的那个任务,并调度它执行。 -
对于普通进程的调度策略SCHED_NORMAL、SCHED_BATCH、SCHED_IDLE:
SCHED_NORMAL:普通的进程。
SCHED_BATCH:后台进程,几乎不需要和前端进行交互,这类进程可以默默执行,不要影响需要交互的进程,可以降低它的优先级。
SCHED_IDLE:是特别空闲的时候才跑的进程。 -
调度策略的执行逻辑,就封装在sched_class中:
stop_sched_class:优先级最高的任务会使用这种策略,会中断所有其他线程,且不会被其他任务打断。
dl_sched_class:对应deadline调度策略。
rt_sched_class:对应RR或FIFO调度策略。
fair_sched_class:普通进程的调度策略。
idle_sched_class:空闲进程的调度策略。 - 对于普通进程,Linux中实现了一个基于CFS(Completely Fair Scheduling,完全公平调度)的调度算法。CFS会为每一个进程安排一个虚拟运行时间vruntime。如果一个进程在运行,随着时间的增长,进程的vruntime将不断增大,没有得到执行的进程的vruntime不变。
-
vruntime经常变化,CFS使用红黑树来对vruntime进行排序,因为红黑树在需要查询的时候,能够快速找到最小的vruntime,更新的时候也能够快速地调整排序。能够平衡查询和更新速度的数据结构是树。
- 包含vruntime的红黑树的节点称为调度实体。运行的进程通过不断地插入操作最终都存储在以时间为顺序的红黑树中,vruntime最小的在树的左侧,vruntime最多的在树的右侧。CFS调度策略会选择红黑树最左边的叶子节点作为下一个将获得CPU的任务。这个红黑树在CPU看起来就是一个队列,不断地取下一个应该运行的进程。
-
在每个CPU上都有一个队列rq,这个队列里面包含多个子队列,如rt_rq和cfs_rq,不同的队列有不同的实现方式,cfs_rq就是用红黑树实现的。当某个CPU需要下一个任务执行时,会按照优先级依次调用调度类,不同的调度类操作不同的队列,其中rt_sched_class先被调用,它会在rt_rq上找下一个任务,只有找不到的时候,才轮到fair_sched_class被调用,它会在cfs_rq上找下一个任务,这样保证了实时任务的优先级永远大于普通任务。
-
调度的方式:主动式调度和抢占式调度。
-
主动调度的过程,也即一个运行中的进程主动调用__schedule函数让出CPU。在__schedule里会做两件事情:第一是选取下一个进程,第二是进行上下文切换。上下文切换又分用户态进程空间(也即虚拟内存)的切换和内核态的切换。