一、调度器分析
1、调度器及其功能
内核中用来安排进程执行的模块称为
调度器(
scheduler
)
,它可以切换进程状态(
processstate
)。例如执行、可中断睡眠、不可中断睡眠、退出、暂停等。
调度器是CPU中央处理器的管理员,专门用来管理时间的,
主要负责完成做两件事情:
一、选择某些就绪进程来执行,
二、是打断某些执行的进程让它们变为就绪状态。调度器分配
CPU时间的基本依据就是进程的优先级。
上下文切换(
contextswitch
):将进程在
CPU中切换执行的过程,内核承担此任务,负责重建和存储被切换掉之前的
CPU
状态。
就绪状态:进程已经获得了CPU以外所有的资源。例如进程空间、网络连接等等。就绪状态的进程等到cpu便可立即执行。
执行状态:进程获得CPU叫执行程序,running状态。
阻塞状态:当进程由于等待某一个事件而无法执行的时候,放弃cpu,这时候就处于阻塞状态。
具体cpu三种状态切换举例说明:
- 进程创建自动进入就绪状态。
- 从执行主动进入阻塞状态:比如一个进程需要把一个磁盘数据读入到内存当中,这段读取的时间里面,进程不需要使用cpu了,可以主动进入阻塞状态,让出cpu。
- 从执行被动进入阻塞状态:比如进程收到sigstop信号。
- 从阻塞状态到就绪状态:比如一个进程需要把一个磁盘数据读入到内存当中,当读取完成时,硬件会发送一个读取完成的信号,进程再次从阻塞状态恢复到就绪状态。
- 从就绪到执行:如果CPU把时间片分配给了就绪状态的进程,那么该进程就从就绪状态变成了执行状态。
调度器如果支持就绪状态切换到执行状态,同时支持执行状态切换到就绪状态,则称为该调度器为抢占式调度器。
2、调度类sched_class结构体与调度类
sched_class结构体表示调度类,定义在kernel/sched/sched.h。
【成员解析】
enqueue_task:向就绪队列添加一个进程,某个进程进入可运行状态时,该函数将会调用,它将调度实体放入到红黑树当中。
dequeue_task: 将一个进程从就绪队列中进行删除,当某个任务退出可运行状态时调用该函数,它将从红黑树中去掉对应调度实体。
yield_task:在进程想要资源放弃对处理器的控制权时,调用在sched_yiled系统调用,会调用内核API去处理。
check_preempt_curr:检查当前运行任务是否被抢占。cfs调度时会进行公平性测试。
pick_next_task:选择下来要运行的最合适的实体(进程)。
put_prev_task: 用于另一个进程代替当前运行的进程。
set_curr_task:当任务修改它调用类或者修改它的任务组时,将调用这个函数。
task_tick:在每次激活周期调度器时,由周期性调度器调用。
调度类:dl_sched_class
、
rt_sched_class
、
fair_sched_class
及
idle_sched_class
等。每种进程都对应每一种调度进程。每一种调度策略对应每一种调度类(每一个调用类可以对应多种调度策略)。
rt_sched_class: 实时调度器(SCHED_FIFO、SCHED_RR)
fair_sched_class: 完全公平调度器(调度策略: SCHED_NORMAL、SCHED_BATCH)
优先级最高的线程,可以中断其它任意线程,不会被其他任务打断。
作用于实时线程
每个cpu的进程pid=0线程,swapper,是一个静态线程。调度类属于idel_sched_class.一般运行在开机过程和cpu异常的时候回做dump。
公平调度器CFS,作用:一般常用线程
SCHED_NORMAL,SCHED_BATCH,SCHED_IDLE直接被映射到fair_sched_class;
SCHED_RR,SCHED_FIFO与rt_schedule_class进行相关联。
Linux调度核心选择下一个合适的task运行时,会按照优先级顺序遍历调度类的pick_next_task函数。
3、优先级
task_struct
结构体中采用三个成员表示进程的优先级:
prio
和
normal_prio
表示动态优先级, static_prio
表示进程的静态优先级。 内核将任务优先级划分,实时优先级范围是0到MAX_RT_PRIO-1(即99),而普通进 程的静态优先级范围是从MAX_RT_PRIO到MAX_PRIO-1(即100到139)。
Linux
内核源码:
/include/linux/sched/prio.h
。
二、完全公平调度器CFS