进程调度
仅用于自学
1.进程调度的概念
进程调度是在多处理器系统下的可以最大限度的利用处理器资源而产生的一种手段
。
2.进程分类
进程分为I/O消耗型和处理器消耗型
I/O消耗型:该进程用于提交I/O请求或是等待I/O,运行时间很短。
处理器消耗型:该进程长时间处于运行代码,运行时间长。
2.1进程优先级
优先级分为两类:静态优先级和动态优先级
静态优先级又称为nice值,nice值的范围-20 -- 19,默认值为0,nice值越大,他的优先级越低,获得的时间片越短。该值在进程创建时就确定下来,不可更改。
动态优先级又名实时优先级,默认范围0 -- 99 ,该值可以配置,任何实时优先级都要高于普通进程。
动态优先级的确定是根据进程的静态优先级和进程交互性的函数计算而来的。
进程的交互性:调度程序需要通过推测来确定该进程是I/O消耗型的还是处理器消耗型的,在进程描述符中记录了进程的执行时间和休眠时间,
记录在
task_struct
的
sleep_avg
域。默认值是
10
毫秒,当进程休眠时该值就增加,没执行一个时钟节拍就会减,直到为0.
2.2进程时间片
进程时间片:进程可以在处理器运行的时间。
当一个进程的时间片耗尽时,该进程就不可运行了,除非等到其他的进程时间片都用完后,重置所有时间片。
时间片的计算:
1.一个进程被创建,父子进程均分时间片。 作用:防止用户不断创建进程来撰取时间片。
2.一个任务的时间片用完时,就根据静态优先级来重新计算时间片。
3.task_timeslice()函数给指定任务返回一个时间片。
3.进程调度
3.1.可执行队列
可执行队列runqueue 是调度程序最基本的数据结构,每个处理器只有一个runqueue,runqueue包含了处理器的调度信息,在对runqueue进行操作时必须对其加锁。
3.2优先级数组
每个runqueue都含有两个优先级数组:活跃的和过期的
活跃的:即时间片未耗尽的进程存放在该数组中。
过期的:当时间片耗尽后,重新计算时间片,在将该进程加入到过期的数组中。
优先级数组是一个prio_array类型的结构体
优先级队列:每一种优先级都有一个相应的一个队列,该队列包含对应优先级的可执行进程的链表。
优先级位图:当前含有的所有优先级,在优先级位图中将其对应的位置为1,在找最高优先级时只需查找最高的位即可。提高查找速度。
3.3重置时间片
正因为有两个优先级数组,活跃的:保存了时间片未耗尽的进程;过期的:保存了重新计算了时间片的进程。当活跃的数组里面的进程为空时,将活跃的数组与过期数组进行交换即可。因为数组是通过指针进行访问的,所以交换消耗的时间就是交换指针消耗的时间,这就实现了0(1)级调度。交换由schedule()来完成。
3.4schedule
schedule功能:选定下一个进程并切换到它去执行。
过程:在活动优先级数组中查找优先级最高的进程,通过优先级位图,确定最高优先级,在对应的优先级队列中取第一个进程。
4.负载平衡程序
4.1负载平衡程序用来实现可执行队列之间的负载均衡
4.2负载平衡程序由load_balance()实现,有两种调用情况
1.在schedule()执行时,如果当前可执行队列为空就去调用负载平衡程序。
2.被定时器调用,系统空闲时每隔1毫秒调用一次或者其他情况每个200毫秒调用一次。
4.3负载均衡在调用时需要锁住可执行队列,防止可执行队列被并发的访问。
4.4负载均衡程序的处理过程
1.找到最繁忙的可执行队列
2.从可执行队列中选择一个优先级数组,最好是过期的。
3.从数组中寻找含有进程且优先级最小的链表。
4.分析找到所有优先级相同的进程,选择一个不是正在运行,也不会因为处理器相关性不可移动,并且不在高速缓冲中的进程,如果满足这些条件,就抽取该进程。
5.如果没平衡就循环执行3,4直到平衡,解除对可执行队列的锁定。