进程调度
- 抢占式操作系统:由调度程序决定一个进程什么时候停止运行以便其他进程可以执行
- 非抢占式操作系统:除非进程主动停止,否则他将一直执行下去
每个进程在抢占之前能够运行的时间叫做时间片,也就是分给每个可运行进程的处理器时间段
策略
- I/O消耗型进程:大部分时间用来提交I/O请求或等待I/O请求
- 处理器消耗性:时间大多用在代码执行上
进程优先级
根据进程的价值对处理器时间需求进行划分。高优先级使用时间片较长,调度程序总选择时间片未用尽且优先级最高的进程来运行。
基于动态优先级调度:先给每个进程设置基本的优先级,再根据需求动态增减;如:进程在等待I/O时间上消耗过多,属于I/O消耗性进程,则优先级动态提高;如果进程的时间片一下全被耗尽则属于处理器消耗性,优先级被动态降低。
两组独立的优先级范围:1.nice值;2.实时优先级,可配置,任何实时进程优先级高于普通进程
时间片
I/O密集型程序不需要产时间的时间片,而处理器消耗性则需要
没必要一次用完时间片,可以分几次用。当进程的时间片消耗完则不会再投入运行,除非其他所有进程时间片都耗尽,此时所有进程时间片会重新计算。
抢占进程
进程处于TASK_RUNNING状态会被抢占、时间片用完会被抢占
Linux调度算法
调度程序中的可执行队列数据结构是处理器上可执行进程的链表,每个处理器一个,每个运行的进程都属于一个可执行队列,可执行队列也包含处理器的调度信心
优先级数组
优先级数组使可运行的处理器每种优先级都包含一个相应的队列,这些队列包含对应优先级上可执行进程链表;优先级位图用来查找系统内最高优先级的进程
MAX_PRIO:优先级个数默认140
BITMAP_SIZE优先级位图数组大小,unsigned long为32位,每位代表一个优先级,则BITMAP_SIZE大小为5;默认每位为0,如优先级为8的进程处于可执行状态,则第八位被置1;查找函数sched_find_first_bit()
活动数组内的进程时间片都有剩余而过期数组内的可执行队列的进程时间片都被耗尽;时间片被耗尽后移到过期数组此时新的时间片已经被计算好,活动与过期的切换就变成指针交换
schedule()
进程被抢占会调用次函数
重新计算时间片
根据初始的nice值+惩罚或奖励值
交互性很强的进程时间片用完后会放入活动数组而不是过期数组
根据nice值判断交互性:值为19交互性再强不会被加入;值为-20不想被加入只能多占用时间片;
如果处于饥饿状态也就是长时间没有发生交换则不会被加入
睡眠和唤醒
如果睡眠前条件已经达成则循环退出;唤醒会等待队列上的所有进程;
有时候存在虚假的唤醒,被唤醒并不是等待的条件达成,所以需要用循环处理保证被唤醒是真正的条件达成
负载平衡
- 首先找到最繁忙队列(如果没有哪个可执行队列中的进程数目比当前队列进程数多25%或以上,则返回NULL)
- 从最繁忙的队列中选一个优先级数组便抽取进程;如果过期数组为空则抽取活动数组
- 找到进程优先级最高的链表
- 在这些优先级相同的进程中,选一个不正在执行的、不在高速缓存的、不是不可以动的,将其从繁忙队列加入当前队列
- 重复以上两步
抢占和上下文切换
- 虚拟内存映射到新的进程
- 处理器状态切到新的进程(保存、恢复栈信息,寄存器信息)
实时
SCHED_FIFO、SCHED_RR;普通的非实时SCHED_NORMAL;
SCHED_FIFO先入先出调度算法不使用时间片,比任何SCHED_NORMAL优先调度,其处于运行态便一直运行直到自己主动退出,或较高优先级的实时进程抢占。几个SCHED_FIFO会轮流执行
SCHED_RR执行完分配的时间片则不会在被运行