进程调度
4.1多任务
1.多任务系统可以划分为:非抢占式多任务和抢占式多任务;
(在此模式下,由调度程序来决定什么时候停止一个进程的运行,以便其他进程能够得到执行机会,这个动作叫抢占;
时间片实际上是分配给可运行进程的处理器时间段 )
(在非抢占多任务模式下,除非进程自己主动停止运行,否则它会一直执行,进程主动挂起自己的操作叫做让步;)
2.进程通常做出让步,以便有很多处理时间,但是这种机制有很多缺点:
调度程序无法对每个进程该执行多久时间做出统一规定,所以进程独占的处理器时间可能超过用户的预料;
一个绝不让步的悬挂就能使系统崩溃
4.2Linux的进程调度
一种叫做O(1)调度程序
4.3策略
调度器的策略往往决定系统的整体印象。而且负责优化使用处理器时间
1.进程可以分为两个类型:I/O消耗型 和处理器消耗型;
前者是指进程的大部分时间用来提交I/O请求或者等待请求,这样的进程经常处于可运行状态,但是时间很短,因为要等待更多I/O请求时,最后会阻塞;
后者是指进程把大部分时间用在执行代码上,除非被抢占,否则他们一直在不停的运行,因为没有太多的I/O需求;
2.调度策略通常要在两个矛盾的目标中间寻找平衡:进程响应迅速和最大系统系统利用率
3.调度算法中一类是基于优先级的调度:调度程序总是选择时间片未用尽而且优先级最高的进程。用户和系统设置进程的优先级来影响系统的调度; Linux两种不同的优先级范围。第一种是nice值,范围从-20到+19,默认值为0;越大的nice值意味着更低的优先级;在Linux中,nice值代表时间片的; 第二种是实时优先级,其值是可配置的,默认情况下它的变化范围是从0到99,与nice值不同,越高的实时优先级数值意味着进程优先级越高;
4.时间片是一个数值,它表明进程被抢占前能持续运行的时间;
时间片过长会导致系统对交互的响应欠佳,让人觉得系统无法并发执行应用程序;
时间片过短会明显增大进程切换带来的处理器耗时,因为肯定会有相当一部分系统时间用在进程切换上,而这些进程能够用来运行的时间片却很短。
I/O消耗型号不需要长的时间片,而处理器消耗型的进程则希望越长越好.
4.4Linux调度算法
1.Linux调度器是以模块方式提供的,这样做的目的是允许不同类型的进程可以有针对性地选择调度算法;
这种模块化结构被称为调度器类,它允许多种不同的可动态添加的调度算法并存,调度属于自己的范畴的进程
2.完全公平CFS,是一个针对普通进程的调度类,在Linux中称为SCHED_NORMAL,CFS算法实现定义在文件kernel/sched_fair.c中
3.unix系统中的进程调度
4.公平调度:
CFS的做法是允许每个进程运行一段时间、循环轮转、选择运行最少的进程作为下一个运行进程,而不再采用分配给每个进程时间片的做法,CFS在所有可运行进程总数进程计算出一个进程应该运行多久,而不是依靠nice值来计算时间片;
*越高的nice值进程获得越低的处理器使用权重,这是相对默认nice值进程而言的;相反,更反的nice值的进程获得更高的处理器使用权重
5.CFS为此引入每个进程获得的时间片底线,这个底线称为最小粒度、默认情况下就是1ms
6.任何进程所获得的处理器时间是由它自己和其他所有可运行进程nice值的相对差值决定的,nice值对时间片的作用不再是算数加权,而是几何加权,任何nice值对应的绝对时间不再是一个绝对值,而是处理器的使用比;CFS称为公平调度是因为确保给每个进程公平的处理器使用比,CFS不是完美的公平,
4.5Linux调度的实现
1.时间记账
CFS使用调度器实体结构(定义在<linux/sched.h>的struct_sched_entity)来追踪进程运行记账;
vruntime变量存放进程的虚拟运行时间,该运行时间的计算是经过了所有可运行进程总数的标准化,因此可用此变量来记录一个程序到底运行了多少时间以及还将运行多久
2.进程选择
CFS调度算法的核心:选择具有最小vruntime的任务
红黑树:挑选下一个任务;向树中加入进程;从树中删除进程
3.调度器入口
调度器的主要入口点是函数schedule(),它定义在文件kernel/sched.c中。它正是内核其他部分用于调用进程调度器的入口
4.睡眠和唤醒
休眠的进程处于一个特殊的不可执行的状态.
1、等待队列
休眠通过等待队列进行处理。等待队列是由等待某些事件发生的进程组成的简单链表;内核用wake_queue_head_t来代表等待队列;函数inotify_read(),负责从通知文件描述符中该读取信息,它的实现无疑是等待队列的典型用法。
2、唤醒
唤醒操作通过函数wake_up()进行,它会唤醒指定的等待队列上的所有进程
4.6抢占和上下文切换
上下文切换,也就是从一个可执行进程切换到另一个可执行进程,由定义kernel/sched.c中的context_switch()函数负责处理
1.用户抢占:从系统调用返回用户空间
从中断处理程序返回用户空间
2.内核抢占:中断处理程序正在执行,且返回内核空间之前
内核代码再一次具有可抢占性的时候
如果内核中的任务显式地调用schedule()
如果内核中的任务阻塞(这样也会导致调用schedule())
4.7实时调度策略
1.两种实时调度策略:sched_fifo和sched_RR;前者实现了一种简单、先入先出的调度算法:它不使用时间片;而后者尽量事先分配给它的时间后就不能再继续执行了。
4.8与调度相关的系统调用