schedule函数总览
void Schedule(void) //在kernel/sched.c中
{while(1) { c=-1; next=0; i=NR_TASKS;p=&task[NR_TASKS];while(--i){ if((*p)->state == TASK_RUNNING&&(*p)->counter>c)c=(*p)->counter, next=i; }if(c) break; //找到了最大的counterfor(p=&LAST_TASK;p>&FIRST_TASK;--p)(*p)->counter=((*p)->counter>>1)+(*p)->priority; }switch_to(next); }
}
这段代码是Linux 0.11内核中的一个任务调度函数,其主要作用是实现操作系统中的任务(进程)调度。任务调度是操作系统的核心功能之一,它负责决定哪个任务应该获得CPU时间片以执行。以下是这段代码的主要功能和用途:
-
循环调度:
while(1)
表示调度函数会无限循环执行,这是典型的操作系统调度器的行为,它会不断地进行任务调度。 -
寻找最高优先级的任务:
-
初始化变量
c
为-1和next
为0,i
为任务总数NR_TASKS
。 -
遍历任务列表,找到状态为
TASK_RUNNING
(正在运行)且counter
值最大的任务,counter
值越大表示优先级越高。 -
如果找到了这样的任务,将
next
设置为该任务的索引,c
设置为该任务的counter
值,并跳出循环。
-
-
时间片调整:
-
如果没有找到正在运行的任务(即所有任务的
counter
值都不大于0),则遍历所有任务,将每个任务的counter
值右移一位(相当于减半),然后加上该任务的优先级值。这是为了实现时间片轮转调度算法,每个任务都会获得执行的机会,但优先级高的任务会更快地获得执行机会。
-
-
任务切换:调用
switch_to(next)
函数,将CPU的控制权切换到next
索引对应的任务。这是通过保存当前任务的上下文并加载下一个任务的上下文来实现的。
counter的作用:时间片
从您提供的图片中提取的代码如下:
void do_timer(...) //在kernel/sched.c中
{if((--current->counter > 0) return;current->counter = 0;schedule();
}
__timer_interrupt: //在kernel/system_call.s中...call do_timer
void sched_init(void) {set_intr_gate(0x20, &timer_interrupt);
}
代码分析
-
do_timer 函数:
-
该函数位于
kernel/sched.c
中。 -
它的作用是处理定时器中断。每当定时器中断发生时,该函数会被调用。
-
函数首先检查当前任务的
counter
值。如果counter
减1后仍然大于0,函数直接返回,不进行任何调度操作。这意味着当前任务仍然有剩余的时间片。 -
如果
counter
减1后等于0,表示当前任务的时间片已经用完,函数将counter
重置为0,并调用schedule()
函数进行任务调度。
-
时间片轮转调度
-
时间片分配:
-
每个进程都被分配一个
counter
值,这个值表示进程可以使用CPU的时间片(或时间量)。 -
当一个进程开始执行时,它的
counter
值开始递减,每次时钟中断都会减少counter
的值。
-
-
时间片耗尽:
-
当进程的
counter
值递减到0时,表示该进程的时间片已经用完。 -
此时,调度器会将该进程的控制权交出,并选择下一个进程来执行。
-
-
进程切换:
-
通过
switch_to
函数,调度器将CPU的控制权从当前进程切换到下一个进程
-
counter的另外的作用:优先级
while (--i) {if ((*p->state == TASK_RUNNING && (*p)->counter > c))c = (*p)->counter, next = i;
}
for (p = &LAST_TASK; p > &FIRST_TASK; --p)(*p)->counter = ((*p)->counter >> 1) + (*p)->priority;
代码分析
-
寻找最高优先级的任务:
-
这段代码遍历任务列表,寻找
counter
值最大的任务。counter
值越大,表示任务的优先级越高。 -
TASK_RUNNING
状态表示任务处于可运行状态,即任务已经准备好并等待CPU时间片来执行。 -
如果找到一个
counter
值大于当前最大值c
的任务,就更新c
和next
变量。next
变量用于记录找到的最高优先级任务的索引。最终找到的就是counter最大的任务。
-
-
动态调整优先级:
-
这段代码遍历所有任务,动态调整每个任务的
counter
值。 -
对于每个任务,将其
counter
值右移一位(相当于除以2),然后加上任务的优先级值。这种调整方式使得counter
值会随着时间的推移而增大 -
这种机制确保了长时间等待的任务(如阻塞在IO上的任务)在再次变为就绪状态时,会获得较高的优先级。
-
优先级动态调整的解释
-
阻塞和非阻塞进程的优先级差异:
-
阻塞进程通常是因为等待IO操作而暂停执行的进程。这些进程在等待IO完成时,无法继续执行,因此它们在就绪队列中等待的时间较长。
-
当这些阻塞进程再次变为就绪状态时,它们的
counter
值会被设置为一个较大的值,从而提高它们的优先级。这种机制确保了这些长时间等待的进程能够更快地获得CPU时间,提高了系统的响应性。
-
-
前台进程的特征:
-
前台进程通常是用户直接交互的进程,它们对响应时间有较高的要求。这些进程往往需要频繁地进行IO操作,如读取用户输入或显示输出。
-
通过提高阻塞进程的优先级,调度器能够更好地满足前台进程的需求,确保它们能够及时获得CPU时间来处理用户请求。
-
counter作用总结
-
保证响应时间:
-
counter
机制确保了系统的响应时间是有界的。这是通过动态调整counter
值来实现的,其中c(t) = c(t-1)/2 + p
表示在每个时间单位t
,counter
值会减半然后加上一个优先级常数p
。最大的counter小于2p
-
-
IO操作后
counter
增大:-
当进程完成IO操作后,其
counter
值会变大。这是因为IO操作通常与前台进程相关,这些进程需要更快的响应时间。counter
值的增大确保了这些进程在再次变为就绪状态时能够获得更高的优先级。
-
-
前台和后台进程的调度:
-
前台进程(通常是与用户交互的进程)在完成IO操作后会获得更高的
counter
值,从而获得更高的优先级。 -
后台进程则继续按照
counter
值进行轮转调度,这种方式近似于最短剩余时间优先(SJF)调度算法,有助于提高系统的吞吐量。
-
总结来说,counter
在Linux 0.11内核中的作用是多方面的,它不仅实现了时间片轮转调度,还通过动态调整优先级来适应不同类型的进程需求。这种设计使得调度算法既简单又高效,能够满足多种任务的调度需求。