一篇文章让你了解Linux进程调度器

1、背景知识1.1 什么是调度器
通常来说 , 操作系统是应用程序和可用资源之间的媒介 。
典型的资源有内存和物理设备 。但是CPU也可以认为是一个资源 , 调度器可以临时分配一个任务在上面执行(单位是时间片) 。调度器使得我们同时执行多个程序成为可能 , 因此可以与具有各种需求的用户共享CPU 。
内核必须提供一种方法, 在各个进程之间尽可能公平地共享CPU时间, 而同时又要考虑不同的任务优先级.
调度器的一个重要目标是有效地分配 CPU 时间片 , 同时提供很好的用户体验 。调度器还需要面对一些互相冲突的目标 , 例如既要为关键实时任务最小化响应时间, 又要最大限度地提高 CPU 的总体利用率.
调度器的一般原理是, 按所需分配的计算能力, 向系统中每个进程提供最大的公正性, 或者从另外一个角度上说, 他试图确保没有进程被亏待.
1.2 调度策略
传统的Unix操作系统的都奥杜算法必须实现几个互相冲突的目标:

  • 进程响应时间尽可能快
  • 后台作业的吞吐量尽可能高
  • 尽可能避免进程的饥饿现象
  • 低优先级和高优先级进程的需要尽可能调和等等
调度策略(scheduling policy)的任务就是决定什么时候以怎么样的方式选择一个新进程占用CPU运行.
传统操作系统的调度基于分时(time sharing)技术: 多个进程以”时间多路服用”方式运行, 因为CPU的时间被分成”片(slice)”, 给每个可运行进程分配一片CPU时间片, 当然单处理器在任何给定的时刻只能运行一个进程.
如果当前可运行进程的时限(quantum)到期时(即时间片用尽), 而该进程还没有运行完毕, 进程切换就可以发生.
分时依赖于定时中断, 因此对进程是透明的, 不需要在承租中插入额外的代码来保证CPU分时.
调度策略也是根据进程的优先级对他们进行分类. 有时用复杂的算法求出进程当前的优先级, 但最后的结果是相同的: 每个进程都与一个值(优先级)相关联, 这个值表示把进程如何适当地分配给CPU.
在linux中, 进程的优先级是动态的. 调度程序跟踪进程正在做什么, 并周期性的调整他们的优先级. 在这种方式下, 在较长的时间间隔内没有任何使用CPU的进程, 通过动态地增加他们的优先级来提升他们. 相应地, 对于已经在CPU上运行了较长时间的进程, 通过减少他们的优先级来处罚他们.
1.3 进程饥饿
进程饥饿 , 即为Starvation , 指当等待时间给进程推进和响应带来明显影响称为进程饥饿 。当饥饿到一定程度的进程在等待到即使完成也无实际意义的时候称为饥饿死亡 。
产生饥饿的主要原因是
在一个动态系统中 , 对于每类系统资源 , 操作系统需要确定一个分配策略 , 当多个进程同时申请某类资源时 , 由分配策略确定资源分配给进程的次序 。
有时资源分配策略可能是不公平的 , 即不能保证等待时间上界的存在 。在这种情况下 , 即使系统没有发生死锁 , 某些进程也可能会长时间等待.当等待时间给进程推进和响应带来明显影响时 , 称发生了进程饥饿 , 当饥饿到一定程度的进程所赋予的任务即使完成也不再具有实际意义时称该进程被饿死 。
举个例子 , 当有多个进程需要打印文件时 , 如果系统分配打印机的策略是最短文件优先 , 那么长文件的打印任务将由于短文件的源源不断到来而被无限期推迟 , 导致最终的饥饿甚至饿死 。
2、linux进程的分类2.1 进程的分类
当涉及有关调度的问题时, 传统上把进程分类为”I/O受限(I/O-dound)”或”CPU受限(CPU-bound)”.
一篇文章让你了解Linux进程调度器

文章插图
 
另外一种分类法把进程区分为三类:
一篇文章让你了解Linux进程调度器

文章插图
 
注意
前面的两类分类方法在一定程序上相互独立
例如, 一个批处理进程很有可能是I/O受限的(如数据库服务器), 也可能是CPU受限的(比如图形绘制程序)
2.2 实时进程与普通进程
在linux中, 调度算法可以明确的确认所有实时进程的身份, 但是没办法区分交互式程序和批处理程序(统称为普通进程), linux2.6的调度程序实现了基于进程过去行为的启发式算法, 以确定进程应该被当做交互式进程还是批处理进程. 当然与批处理进程相比, 调度程序有偏爱交互式进程的倾向


推荐阅读