3.1策略
3.1.1I/O消耗型和处理器消耗型.
进程可以分为I/O消耗型和处理器消耗型.
I/O消耗型经常处于提交I/O请求或是等待I/O请求.
处理器消耗型大部分用于执行代码上.
进程调度两个目标:进程响应迅速,里程吞吐量高.
linux为了保证响应时间,更倾向于优先调度I/O消耗型进程.
3.1.2进程优先级
优先级高的先运行,低的后运行.高的时间片长,低的短.linux实现了
基于动态优先级的调度方法.
:一开始设定基本的优先级.然后根据调度程序加减优先级.
linux 内核提供两组独立的优先级范围.
1.nice值.nice值越大(be nice),优先级越低.
2.实时优先级.
3.1.3时间片
时间片长,影响交互,时间片短,效率低.
根据进程的优先级动态的调整分配给它的时间片.从而保证优先级高
的进程,重要性高的进程,执行频率高,执行时间长.
3.1.4进程抢占
一个TASK_RUNNING的进程如果比当前进程的优先级高,那么高度程序
会被唤醒,重新选择此进程执行.
如果一个进程的时间片为0,那么它将被抢占.
3.1.5调度策略的活动
合理分配优先级,时间片,最大程序优化性能.
3.2调度算法3.2.1可执行队列
调度程序中最基本的数据结构是运行队列.(runqueue)定义在
kernel/sched.c中.每个处理器一个运行队列.
struct runqueue
{}
可执行队列是调度程序的核心数据结构,所以有一组宏用于获取给定
的可执行队列.
1.cpu_rq(processor)给定CPU的可执行队列的指针.
2.this_rq();返回当前处理器的可执行队列.
3.task_rq(task);给定任务所在的可执行指针.
this_rq_lock()
rq_unlock()
为了避免死锁,要锁住多个运行队列的代码必须总是按照同样的顺序
获得这些锁.如下列从小到大顺序:
if(rq1<rq2)
{
spin_lock(&rq1->lock);
spin_lock(&rq2->lock);
}else
{
spin_lock(&rq2->lock);
spin_lock(&rq1->lock);
}
3.2.2优先级数组
每个运行队列都有两个优先级数组.一个活跃的一个过期的.
优先级数组使可运行处理器的每一种优先级都包含一个相应的队列,
这些队列包含此优先级上的可执行里程链表.
struct prio_array{
int nr_active;
unsigned long bitmap[BITMAP_SIZE];
struct list_head queue[MAX_PRIO];
}
位图bitmap有五个数据项,共160位,默认为140位有用.代表140个优
先级.当某个拥有一定优先级的进程状态变为TASK_RUNNING,位图中
相应的位就会被置为1.这样,查找系统中最高的优先级就变成了查
找位图中被设置的第一个位。因为优先级个数是个定值,所以查找
时间恒定,并不受系统到底有多少可执行进程的影响。
3.2.3重新计算时间片
当一个进程的时间片耗尽时,它会被移至过期数组,但在此之前,
时间片已经给它重新计算好了。当活动数组中没有剩余进程的时候
,这两个数组就会被交换,活动数组变成过期数组,过期数组替代
活动数组。如果一个进程的交互性非常强,那么当它时间片用完后
,它会被再放置到活动数组而不是过期数组中。
schedule()调度过程
schedule()---->sched_find_first_bit()打到当前最高优先级--->
调度程序选择这个级别里的第一个进程.
3.2.4计算优先级和时间片