常把进程分为以下三类:
交互式进程(Interactive process)
批处理进程(Batch process)
实时进程(Real-time process)
Linux2.6 内核是抢占式的,这意味着进程无论是处于内核态还是用户态,都可能被抢占。
调度程序总能成功地找到要执行的进程,事实上,总是至少有一个可运行进程:即swapper 空闲进程,它的PID等于0,而且它只有在CPU不能执行其他进程时才执行。
每个Linux进程总是按照下面的调度类型被调度:
SCHED_FIFO
先进先出的实时进程,此特性只有在具备相同优先级的实时进程间体现。当调度程序把CPU分配给进程的时候,它把该进程描述符保留在运行队列链表的当前位置。如果没有其他可运行的高优先权实时进程,进程就继续使用CPU, 想用多久就用多久,即使还有其他具有相同优先权的实时进程处于可运行状态。(sched_rr 为2)
SCHED_RR
时间片轮转的实时进程。当调度程序把CPU分配给进程的时候,把该进程的描述符放在运行队列链表的末尾。这种策略保证对所有具有相同优先权的SCHED_RR实时进程公平地分配CPU 时间。(sched_fifo 为1)
SCHED_NORMAL
普通的分时进程。(sched_normal 或者 sched_other是Linux默认的调度策略,其值为0)
其中后两个为实时进程的调度策略,第一个是非实时进程的调度策略。
(1)与调度相关的系统调用
nice( ) 改变一个普通进程的静态优先级
getpriority( ) 获得一组普通进程的最大优先级
setpriority( ) 设置一组普通进程的静态优先级
sched_getscheduler( ) 获得一个进程的调度策略
sched_setscheduler( ) 设置一个进程的调度策略和实时优先级
sched_getparam( ) 获得一个进程的实时优先级
sched_setparam( ) 设置一个进程的实时优先级
sched_yield( ) 自愿放弃处理器而不阻塞
sched_get_ priority_min( ) 获得一种策略的最小实时优先级
sched_get_ priority_max( ) 获得一种策略的最大实时优先级
sched_rr_get_interval( ) 获得时间片轮转策略的时间片值Linux内核为每个创建的进程分配时间片并根据其优先级进行调度。
(二)进程优先级
linux2.6内核将任务优先级进行了一个划分:
0——99 实时进程
100——139 非实时进程
当进程被创建时,其对应的task_struct里包含了四个优先级:
struct task_struct
{
……3. static_prio指的是任务的静态优先级,在进程创建时分配,该值会影响分配给任务的时间片的长短和非实时任务动态优先级的计算。
静态优先权本质上决定了进程的基本时间片因此静态优先权越高,基本时间片就越长。
动态优先权是调度程序在选择新进程来运行的时候使用的数。它与静态优先权的关系用下面的经验公式表示。
动态优先权=max(100,min (静态优先权-bonus +5,139))
Bonus 是范围从0到10的值,bonus的值小于5表示降低动态优先权以示惩罚,bonus的值大于5表示增加动态优先权以示额外奖赏。Bonus的值依赖于进程过去的情况,说得更准确一些是与进程的平均睡眠时间相关。
平均睡眠时间也被调度程序用来确定一个给定进程是交互进程还是批处理进程。高优先权进程比低优先权进程更容易成为交互进程。
static_prio = MAX_RT_PRIO + 20 + nice(nice的缺省值是0,范围[20, 19])
rt_priority缺省值为0,表示非实时任务。[1,99]表示实时任务;
对于一个实时进程,有两个参数来表明优先级:prio 和 rt_priority。
prio才是调度所用的最终优先级数值,这个值越小,优先级越高;
rt_priority 被称作实时进程优先级,它要经过转化prio=MAX_RT_PRIO - 1- p->rt_priority;
MAX_RT_PRIO = 99;
这样意味着rt_priority值越大,优先级越高;
内核提供的修改优先级的函数,是修改rt_priority的值,所以越大,优先级越高。
调度策略也是根据进程的优先级对它们进行分类:
在Linux 中,进程的优先级是动态的,但对于实时进程,其优先级固定,保证其有固定的时间响应。调度程序跟踪进程正在做什么,并周期性地调整它们的优先级。在这种方式下,在较长的时间间隔内没有使用CPU 的进程,通过动态地增加它们的优先级来提升它们。相应地,对于已经在CPU 上运行了较长时间的进程,通过减少它们的优先级来处罚它们。普通进程的优先级是由动态优先权和静态优先权组合的,而动态优先权会随之运行时间的增加而减少,所以整体上其优先级会下降,以便让其他非实时进程运行。
(3)进程调度时机
Linux调度时机主要有:
1、进程状态转换的时刻:进程终止、进程睡眠;
2、当前进程的时间片用完时(current->counter=0);
3、设备驱动程序主动调用schedule;
4、进程从中断、异常及系统调用返回到用户态时;
(4)改变进程的优先级
进程调度的依据,在每个进程的task_struct结构中有这么五项:
need_resched、nice、counter、policy 及rt_priority
need_resched: 在调度时机到来时,检测这个域的值,如果为1,则调用schedule() 。
counter: 进程处于运行状态时所剩余的时钟滴答数,每次时钟中断到来时,这个值就减1。当这个域的值变得越来越小,直至为0时,就把need_resched 域置1,因此,也把这个域叫做进程的“动态优先级”。
nice: 进程的“静态优先级”,这个域决定counter 的初值。只有通过nice(), sched_setparam()系统调用才能改变进程的静态优先级。
rt_priority: 实时进程的优先级
policy: 从整体上区分实时进程和普通进程,
实时进程应该先于普通进程而运行。
可以通过系统调用sched_setscheduler( )来改变调度的策略。对于同一类型的不同进程,采用不同的标准来选择进程。
对于普通进程,选择进程的主要依据为counter和nice 。
对于实时进程,Linux采用了两种调度策略,即FIFO(先来先服务调度)和RR(时间片轮转调度)