全部博文(18)
分类: LINUX
2009-04-02 22:31:57
抢占式多任务模式——由调度程序来决定什么时候停止一个进程的运行以便其他进程能够执行;
时间片——进程在被抢占之前能够运行的时间是预先设置好的。
4.1 策略
进程——(1) I/O消耗型:进程大部分时间用来提交I/O请求或等待I/O请求
(2) 处理器消耗型:进程大部分时间用来执行代码
优先级范围——(1) nice值,-20~+19,值越大优先级越低,获取的时间片越短
(2) 实时优先级,0~99,实时进程的优先级高于普通进程
进程的时间片耗尽时就会挂起,等到其他所有进程都耗尽各自的时间片后,所有进程的时间片会重新计算
4.2 Linux调度算法
调度程序kernel/sched.c
4.2.1 可执行队列
调度程序中的基本数据结构是运行队列
|
4.2.2 优先级数组
每个运行队列有俩个优先级数组,一个是活跃的,一个是过期的。
struct prio_array {
int nr_active; /* number of tasks in the queues任务数目 */
unsigned long bitmap[BITMAP_SIZE]; /* priority bitmap 优先级位图*/
struct list_head queue[MAX_PRIO]; /* priority queues 优先级队列*/
};
4.2.3 重新计算时间片
两个优先级数组,当一个进程时间片耗尽时,将之移至过期数组,且新的时间片已经计算好,最终切换两数组。
struct prio_array *array = rq->active;
if (!array->nr_active) {
rq->active = rq->expired;
rq->expired = array;
}
4.2.4 schedule()
选定下一个进程并切换去执行之。
判断谁是优先级最高的进程:
struct task_struct *prev, *next;
struct list_head *queue;
struct prio_array *array;
int idx;
prev = current;
array = rq->active;
idx = sched_find_first_bit(array->bitmap);
queue = array->queue + idx;
next = list_entry(queue->next, struct task_struct, run_list);
首先,要在活动优先级数组中找到第一个被设置的位,该位对应着优先级最高的可执行进程,然后,调度程序选择这个级别链表中的头一个进程,即系统中优先级最高的可执行程序,夜就是马上会被调度执行的进程。
4.2.2 优先级数组
每个运行队列有俩个优先级数组,一个是活跃的,一个是过期的。
struct prio_array {
int nr_active; /* number of tasks in the queues任务数目 */
unsigned long bitmap[BITMAP_SIZE]; /* priority bitmap 优先级位图*/
struct list_head queue[MAX_PRIO]; /* priority queues 优先级队列*/
};
4.2.3 重新计算时间片
两个优先级数组,当一个进程时间片耗尽时,将之移至过期数组,且新的时间片已经计算好,最终切换两数组。
struct prio_array *array = rq->active;
if (!array->nr_active) {
rq->active = rq->expired;
rq->expired = array;
}
4.2.4 schedule()
选定下一个进程并切换去执行之。
判断谁是优先级最高的进程:
struct task_struct *prev, *next;
struct list_head *queue;
struct prio_array *array;
int idx;
prev = current;
array = rq->active;
idx = sched_find_first_bit(array->bitmap);
queue = array->queue + idx;
next = list_entry(queue->next, struct task_struct, run_list);
首先,要在活动优先级数组中找到第一个被设置的位,该位对应着优先级最高的可执行进程,然后,调度程序选择这个级别链表中的头一个进程,即系统中优先级最高的可执行程序,夜就是马上会被调度执行的进程。
4.2.6、休眠
等待队列——wait_queue_head_t
创建:DECLARE_WAITQUEUE()或者init_waitqueue_head()
唤醒
函数:wake_up()
步骤:(1) 调用try_to_wake_up()
(2) 设置状态TASK_RUNNING
(3) activate_task()放入可执行队列
(4) 设置need_resched标志(条件:被唤醒进程优先级高)
|
4.2.7、负载平衡程序
每个处理器有自己的进程链表 => 调度系统对每个处理器来看是独立的
多处理器系统,负载不均衡的情况 => 负载平衡程序 => 将繁忙队列中进程抽调到非繁忙队列中
函数:load_balance()
两种调用方法:schedule()执行时,当前可执行队列为空;
定时器调用(系统空闲或其他情况下)。
步骤:(1) find_busiest_queue();
(2) 从最繁忙可执行队列中选一个优先级数组;
(3) 寻找含有进程且优先级最高的链表;
(4) 选择不在执行、不因处理器相关性而不可移动的、不再高速缓存中的进程,pull_task();
(5) 重复3、4步,消除不平衡后解锁当前队列。
|
4.4、实时
两种实时调度策略:
(1) SCHED_FIFO——不使用时间片;比所有SCHED_NORMAL(普通非实时策略)级进程优先级都高;一直执行;多个同级进程情况下轮流执行;
(2) SCHED_RR——带时间片的SCHED_FIFO
这两种实时算法都是静态优先级,内核不计算它们的动态优先级。