1)初识调度
为配合系统对进程的调度,采用两种方式进行处理
1.1)协同多任务处理
当进程因为事件的等待,而自动放弃CPU资源,而使其它进程得以使用CPU,这时称之为协同多任务处理.
其实如果进程都采用协同多任务处理时,系统将会轻松的调度进程,以分配资源
1.2)抢先式多任务处理
当进程不进行I/O,比如计算型运算应用时,一直占用大量的CPU时间,这时系统将会利用中断,使原占用CPU的进程放弃CPU.
这时称之为抢先式多任务处理
1.3)总结
1.3.1)UNIX/LINUX采用协同多任务处理与抢先式多任务处理相结合的方式处理进程.
1.3.2)当进程都采用协同多任务处理,系统就可能永远不会用到抢先式.
1.3.3)调度程序本身也是一个进程,PID是0,是INIT进行的父进程
2)阻塞,抢先占用和放弃
2.1)抢先占用的触发:
2.1.1)当一个进程因为它的时间片用完而被内核停止执行时,就说这个进程被抢占.
2.1.2)当一个享有更高优先公的进程在就绪队列,内核同样可以抢占正在执行的进程,即使它的时间片还没用完.
2.2)放弃的触发:
2.2.1)用户进程可以通过sched_yield系统调用来放弃使用CPU.
2.2.2)用户进程通过其它系统调用来放弃CPU.
例如:一个进程正在调用read/write时,它很可能不得不等待相应的设备的响应,这时它应用使自己睡眠(sleep),放弃CPU,直到设备就绪为止.
2.3)阻塞的触发:
2.3.1)当进程在内核模式下等待一个事件时,就是阻塞,直到所等侍的事件来唤醒它为止.
2.4)总结:
2.4.1)阻塞与放弃的区别
一个阻塞的进程即不会占用CPU,也不会被调度程序调度.而放弃的进程则会被调度程序调度.
2.4.2)linux2.6内核是一个可抢先占有的内核,在不可抢先有的内核则高优先级的进程不能抢占低优先级的进程.
3)优先级
3.1)动态优先级
因为高优先级的进程总比低优先级的进程先被调度,为防止有多个高优先级且一直占用CPU资源,导致其它进程不能占用CPU,所以引用动态优先级概念.
3.2)交互式的进程
如果某个进程被认为是交互式的,那么将被赋予较高的优先权,例如:键盘输入.交互式的进程从来不被抢占,并且占用CPU很少,它们常常自动放弃CPU.
3.3)有效优先级
进程的有效优先级就是静态优先级与额外值的和.
静态优先级是在系统创建时就已经分配给进程了,整个运行周期里不变.
额外值是一个可正可负的值,也可以把额外值理解为动态优先级,因为系统通过改变这个额外值(动态优先级)来改变进程的有效优先级.
额外值是由内核来管理
3.4)用一个例子来说明系统是如何给进程分配动态优先级的
新建nicegy脚本,这个脚本用sleep使其部分时间在睡眠状态.
#!/bin/sh
while true; do
sleep .1
done
新建cruncher脚本,这个脚本在循环中使用true,一直占用CPU.
#!/bin/sh
while true; do
true
done
新建脚本runex,这个脚本使行cruncher和niceguy两个脚本,监控这两个脚本的动态优先级.
#!/bin/sh
./cruncher &
./niceguy &
trap 'echo stoping; kill %1 %2; break' SIGINT
while true; do
ps -C niceguy -C cruncher -o etime,pid,pri,cmd
sleep .5
done
运行runex
./runex
ELAPSED PID PRI CMD
00:00 2343 20 /bin/sh ./cruncher
00:00 2344 21 /bin/sh ./niceguy
ELAPSED PID PRI CMD
00:01 2343 20 /bin/sh ./cruncher
00:01 2344 22 /bin/sh ./niceguy
ELAPSED PID PRI CMD
00:01 2343 19 /bin/sh ./cruncher
00:01 2344 22 /bin/sh ./niceguy
ELAPSED PID PRI CMD
00:02 2343 18 /bin/sh ./cruncher
00:02 2344 23 /bin/sh ./niceguy
ELAPSED PID PRI CMD
00:02 2343 15 /bin/sh ./cruncher
00:02 2344 23 /bin/sh ./niceguy
ELAPSED PID PRI CMD
00:03 2343 14 /bin/sh ./cruncher
00:03 2344 23 /bin/sh ./niceguy
ELAPSED PID PRI CMD
00:04 2343 14 /bin/sh ./cruncher
00:04 2344 23 /bin/sh ./niceguy
结论:
1)这两个进程会随时时间变化而变化
进程cruncher会一直运行不休眠(sleep),因此调度程序会给它一个负的额外值以降低它的有效优先级.
而进程niceguy大部从那时间则处于休息状态,因此调度程序会给它一个正的额外值以提高它的有效优先级.
2)而这两个进程在此之后就处于相对稳定的状态.
3)PRI是有效优先级,系统不能改变进程的静态优先级,但可以改变它的额外值以达到降低有效优先级的目的.
例如:静态优先级是20,额外值是-6,则有效优先级就是PRI=20+(-6)=14,注意这里没有涉及nice值,我们下面再来谈nice值对优先级的影响.
4)nice值与有效优先级
4.1)nice值的由来
内核允许用户通过使用一个名为nice的数值来影响调度程序关于优先级的调度
也就是说nice值是用户来触发,而我们上面说的额外值是内核来触发的.
4.2)nice值对有效优先级的影响
nice值越高,有效优先级就越低.
nice值越低,有效优先级就越高.
有效优先级=静态优先值+额外值-nice值
例如:
静态优先值为20
额外值为-6
nice值为-10
那最后有效优先级就是:
PRI=20+(-6)-(-10)=24
而如果nice值为10
PRI=20+(-6)-10=4
4.3)nice与有效优先级的范围
nice的范围是-20到19
有效优先级的范围是0-39
4.4)例子:nice是如何影响有效优先级的
cruncher进程的有效优先级是14,nice值是0
ps -C cruncher -o etime,pid,pri,ni,cmd
ELAPSED PID PRI NI CMD
00:17 6034 14 0 /bin/sh ./cruncher
更改nice值为-20
renice -20 -p 6034
6034: old priority 0, new priority -20
当nice的值为-20,PRI的值变成34
PRI = 静态优先级(20) + 附加值(-6) - nice(-20) = 34
ps -C cruncher -o etime,pid,pri,ni,cmd
ELAPSED PID PRI NI CMD
00:39 6034 34 -20 /bin/sh ./cruncher
更改nice的值为19
renice 19 -p 6034
6034: old priority -20, new priority 19
当nice的值为19,PRI的值为0
PRI = 静态优先级(20) + 附加值(-6) - nice(19) = 0 因为最低0,即使是-5最后也0
ps -C cruncher -o etime,pid,pri,ni,cmd
ELAPSED PID PRI NI CMD
01:03 6034 0 19 /bin/sh ./cruncher
注意:PRI为34时,系统的反应会变慢.
5)实时优先级
5.1)实时优先级概述:
linux提供了一个实时调度策略,提供了100个额外优先级别,以保证系统能及时响应进程.
5.2)实时优先级和普通优先级的区别:
实时优先级比普通优先级高,普通优先级是0-39.而实时优先级是(41-139),优先级一般不用40.
实时优先级在整个进程的生命周期里是不变的,所以实时进程没有nice值,也没有额外值.它的有效优先级就是静态优先级.
5.3)POSIX标准为实时进程指定了两种策略:先进先出(FIFO),时间片法(Round_Robin,简称RR)
5.3.1)先进先出(FIFO)调度
如果有两个同优先级的进程位于就绪队列,通常情况下,排在前面的先被执行
FIFO的策略要求进程不能抢占CPU,除非另一个实时进程有更高优先级
5.3.2)FIFO调度的例子
这个程序将永远不会退出.系统将会死机.
新建chewer脚本
#!/bin/sh
(sleep 50;kill -ALRM $$) &
while true;do
true;
done
程序为什么不在50秒之后退出呢,原因是一个fifo的调度,是不会运行(sleep 5;kill -ALRM $$),而永远进入了一个死循环.
在2.6.18的内核中,这个会造成死机,而新的2.6.32内核则不会,我们依然有机会终止它.
我们在2.6.32的内核中看下它的优先级
指定调度策略为FIFO,优先级为50
chrt -f 50 ./chewer &
[2] 2414
查看优先级,CLS显示了调度策略,chewer的调度策略是FF,FF表示FIFO,PTRPIO是实时优先级,这里chewer是50,
PRI是有效优先级,在实时系统里也叫绝对优先级,有效优先级是实时优先级与40的和,所以这里是90.
ps -eo pid,ppid,tid,class,rtprio,ni,pri,psr,pcpu,stat,wchan:14,command
PID PPID TID CLS RTPRIO NI PRI PSR %CPU STAT WCHAN COMMAND
1 0 1 TS - 0 19 0 0.0 Ss poll_schedule_ init [2]
2 0 2 TS - 0 19 0 0.0 S kthreadd [kthreadd]
3 2 3 FF 99 - 139 0 0.0 S migration_thre [migration/0]
4 2 4 TS - 0 19 0 0.0 S ksoftirqd [ksoftirqd/0]
5 2 5 TS - 0 19 0 0.0 S worker_thread [events/0]
6 2 6 TS - 0 19 0 0.0 S worker_thread [khelper]
11 2 11 TS - 0 19 0 0.0 S async_manager_ [async/mgr]
58 2 58 TS - 0 19 0 0.0 S bdi_sync_super [sync_supers]
60 2 60 TS - 0 19 0 0.0 S bdi_forker_tas [bdi-default]