第四章 进程调度

  调度程序负责决定将哪个程序投入运行,何时运行以及运行多长时间。进程调度程序可看做在可运行态进程之间分配有限的处理器时间资源的内核子系统。调度程序是像Linux这样的多任务操作系统的基础。

一、多任务

1.多任务操作系统:

  能同时并发地交互多个进程的操作系统。可划分两类:

  • 非抢占式多任务
  • 抢占式多任务

2.抢占:调度程序决定什么时候停止一个进程的运行,以便其他进程能够得到执行机会。

时间片:进程在被抢占之前能够运行的时间。时间片实际上就是分配给每个可运行进程的处理器时间段。

 让步:进程主动挂起自己的操作

二、Linux的进程调度

  Linux内核中的调度程序是一种叫做O(1)的新调度程序

  • 优点:解决了先前版本的许多不足,静态时间片算法和针对每一处理器的运行队列,拜托了先前设计上的限制。
  • 缺点:对于交互程序先天不足

三、策略

1.I/O消耗型和处理器消耗型的进程

  • I/O消耗型进程

  进程的大部分时间用来提交I/O请求或者等待I/O请求

  多数用户图形界面(GUI)都属于I/O密集型

  • 处理器耗费型

  时间大多数用在执行代码上
  
  往往要延长运行时间并降低调度频率

2.进程优先级  

  基于优先级的调度:优先极高的进程先运行;相同优先级的进程按照轮转方式进行调度;优先级分为两类:

  • nice值(从-20——+19):默认值为0;数值越大意味着优先级越低;可以通过 ps-el查看系统进程列表并找到NI标记列对应的优先级
  • 实时优先级(从0——99):越高的实时优先级级数意味着进程优先级越高二者互不交互

3.时间片

  • 时间片表示进程在被抢占之前所能够持续运行的时间;调度策略必须确定一个默认的时间片;
  • Linux的CFS调度器并没有直接划分时间片到进程,而是将处理器的使用比例划分给了进程。也就是说,其抢占时机取决于新的可执行程序消耗了多少处理器使用比,如果消耗的使用比比当前进程小,则新进程立即投入运行抢占当前进程。

四、Linux调度算法

1.调度器类:Linux调度器是以模块方式提供的,目的是允许不同类型的进程可以有针对性地选择调度算法

  • 调度器类允许多种不同的可动态添加的调度算法并存,调度属于自己范畴的进程;
  • 调度器代码会按照优先级顺序遍历调度类,拥有一个可执行进程的最高优先级的调度器类胜出,去选择下面要执行的那一个程序;

2.Unix中系统调度问题

  • 将nice值映射到时间片的话,就必须将nice值对应到处理器的绝对时间;这样会导致进程切换无法最优进行;
  • 如果使用相对nice值,所带来的效果将会极大取决于其nice的初始值;
  • 如果执行nice值到时间片的映射,时间片极大受制于定时器。

3.公平调度
  CFS基于一个简单的理念:进程调度的效果应当如同系统具备一个理想中的完美任务处理器。CFS的做法如下:

  • 允许每个进程运行一段时间、循环轮转、选择运行最少的进程作为下一个运行进程;
  • nice值作为进程获得的处理器运行比的权重(而不是完全由nice决定时间片);
  • 每个进程都按照其权重在全部的可运行进程中所占的比例对应的“时间片”来运行

五、Linux调度的实现

1.CFS得以实现的四个组成部分

  • 时间记账
  • 进程选择
  • 调度器入口
  • 睡眠和唤醒

2.时间记账

  所有的调度器都必须对程序运行的时间做记账。

  • 调度器实体结构:CFS使用调度器实体结构来追踪进程运行记账
  • 虚拟实时:vruntime变量存放进程的虚拟运行时间,虚拟时间以ns为单位,和节拍定时器无关
  • update_curr()函数实现了记账功能;计算了当前进程的执行时间并将其存放在data_exec中;然后将运行时间传递给了_update_curr(),由后者再根据当前可运行进程总数对运行时间进行计算,最终确定上述的权重值与当前运行进程的vrntime。

3.进程选择

  • CFS调度算法的核心:选择具有最小vruntime的任务
  • CFS使用红黑树(自平衡二叉搜索树)组织可运行进程队列
  • 步骤:

    1.选择下一个任务:从根节点中序遍历二叉树,一直到叶子节点(也就是vrntime最小的进程);

    2.向树中加入进程:在进程变为可执行状态或者通过fork()调用第一次创建进程;

    3.从树中删除进程:发生在进程阻塞或者终止的时。

4.调度器入口

  • 进程调度的主要入口点是函数schedule(),定义在kernel/sched.c中;这正是内和其他部分用于调度进程调度器的入口
  • 这一函数最重要的工作就是调用pick_next_state(),依次检查每一个调度类,并从最高优先级的调度类中,选择最高优先级进程

5.睡眠和唤醒

(1)休眠的进程处于一个特殊的不可执行的状态

    休眠的原因:为了等待一些事件

  • 一段时间从I/O读更多数据,或某个硬件事件
  • 一个进程还有可能在尝试获取一个已被占用的内核信号量时被迫进入休眠
  • 文件I/O—如进程对一个文件执行了read()操作,而需要从磁盘读取

(2)等待队列

  • 由等待某些事件发生的进程组成的链表,内核用wake_queue_head_t来代表等待队列
  • 可通过DECLARE_WAITQUEUE()静态创建,也可以由init_waitqueue_head()动态创建

(3)唤醒

  • 唤醒操作通过函数wake_up()进行,它会唤醒等待队列上的所有进程
  • 它会调用函数try_to _wake_up()将进程设置为TASK_RUNNING状态,调用enqueue_task()将进程放入红黑树中
  • 也存在虚假的唤醒

六、抢占和上下文切换

  上下文切换:从一个可执行程序进程切换到另一个可执行程序进程,由定义在kernel/sched.c中的context_switch()函数负责,每当一个新的进程被选出来准备运行的时候,schedule()就会调用该函数。完成两项基本工作:

  • 调用switch_mm(),负责把虚拟内存从上一个进程映射切换到新的进程中;
  • 调用switch_to(),负责从上一个进程的处理器状态切换到新进程的处理器状态。

(1)用户抢占

  • 从系统调返回用户空间时
  • 从中断处理程序返回用户空间时

(2)内核抢占

  • 中断处理程序正在执行,且返回内核空间之前
  • 内核代码再一次具有可抢占性的时候
  • 内核中的任务显式地调用schedule函数
  • 内核中的任务阻塞

七、实时调度策略

  Linux提供了两种实时调度策略,两种都是静态优先级:

  • SCHED_FIFO—简单地、先入先出调度算法,不使用时间片
  • SCHED_RR—带有时间片的SCHED_FIFO算法,实时轮流调度算法

《Linux内核设计与实现》第4章读书笔记的更多相关文章

  1. 《Linux内核设计与实现》第四周读书笔记——第五章

    <Linux内核设计与实现>第四周读书笔记--第五章 20135301张忻 估算学习时间:共1.5小时 读书:1.0 代码:0 作业:0 博客:0.5 实际学习时间:共2.0小时 读书:1 ...

  2. LINUX内核设计与实现第三周读书笔记

    LINUX内核设计与实现第三周读书笔记 第一章 LINUX内核简介 1.1 Unix的历史 1969年的夏天,贝尔实验室的程序员们在一台PDR-7型机上实现了Unix这个全新的操作系统. 1973年, ...

  3. 《Linux内核设计与实现》Chapter 3 读书笔记

    <Linux内核设计与实现>Chapter 3 读书笔记 进程管理是所有操作系统的心脏所在. 一.进程 1.进程就是处于执行期的程序以及它所包含的资源的总称. 2.线程是在进程中活动的对象 ...

  4. 《Linux内核设计与实现》Chapter 1 读书笔记

    <Linux内核设计与实现>Chapter 1 读书笔记 一.Unix的特点 Unix从Multics中产生,是一个强大.健壮和稳定的操作系统. 特点 1.很简洁 2.在Unix系统中,所 ...

  5. 《Linux内核设计与实现》Chapter 2 读书笔记

    <Linux内核设计与实现>Chapter 2 读书笔记 一.获取内核源码 1.使用Git 我们曾经在以前的学习中使用过Git方法 $ git clone git://git.kernel ...

  6. 《Linux内核设计与实现》Chapter 5 读书笔记

    <Linux内核设计与实现>Chapter 5 读书笔记 在现代操作系统中,内核提供了用户进程与内核进行交互的一组接口,这些接口的作用是: 使应用程序受限地访问硬件设备 提供创建新进程与已 ...

  7. 《Linux内核设计与实现》Chapter 18 读书笔记

    <Linux内核设计与实现>Chapter 18 读书笔记 一.准备开始 一个bug 一个藏匿bug的内核版本 知道这个bug最早出现在哪个内核版本中. 相关内核代码的知识和运气 想要成功 ...

  8. Linux内核设计与实现第十周读书笔记

    第十七章 设备与模块 关于设备驱动与设备管理,我们讨论四种内核成分. 设备类型 模块 内核对象 sysfs 17.1设备类型 在Linux以及所有Unix系统中,设备被分为以下三种类型: 块设备,块设 ...

  9. Linux内核设计与实现第八周读书笔记

    第四章 进程调度 进程在操作系统看来是程序的运行态表现形式. 4.1多任务 多任务操作系统就是能同时并发地交互执行多个进程的操作系统. 多任务操作系统会使多个进程处于堵塞或者睡眠状态.这些任务尽管位于 ...

  10. Linux内核设计与实现第六周读书笔记

    第三章 进程管理 3.1 进程 进程是处于执行期的代码.通常进程还要包含其他资源,像打开的文件.挂起的信号.内核的内部数据.处理器状态.一个或多个具有内存映射的内存地址空间及一个或多个执行线程,当然还 ...

随机推荐

  1. play-with-vim1~5

    1.移动 h,j,k,l分别对应左下上右 2.模式 vim有四种模式:普通模式,插入模式,可视模式,命令行模式 进入vim 默认为普通模式,光标为方块 输入i 进入插入模式,窗口左下角为insert ...

  2. 可道云kodexplorer搭建私有云后的配置优化

    一.上传下载速度优化首先明确可道云没有对上传下载做任何限制,速度快慢和网络环境有关.可道云是基于http上传,所以和其他http上传速度基本一致:可以对比其他web系统或网站说附件上传速度.同其他例如 ...

  3. Ubuntu下LimeSDR Mini使用说明

    本文内容.开发板及配件仅限用于学校或科研院所开展科研实验! 淘宝店铺名称:开源SDR实验室 LimeSDR链接:https://item.taobao.com/item.htm?spm=a230r.1 ...

  4. 新手Python第一天(接触)

    Python 变量 Python的变量由字母,数字,下划线组成不包含特殊字符,不能以数字开头 可以使用的名称 例如:name,name2,my_name 不可使用的名称 例如:if...(Python ...

  5. MCS锁——可伸缩的自旋锁

    在编写并发同步程序的时候,如果临界区非常小,比如说只有几条或几十条指令,那么我们可以选择自旋锁(spinlock).使用普通的互斥锁会涉及到操作系统的调度,因此小临界区一般首选自旋锁.自旋锁的工作方式 ...

  6. rename命令详解

    基础命令学习目录首页 原文链接:http://man.linuxde.net/rename 将main1.c重命名为main.c rename main1.c main.c main1.c renam ...

  7. centos下设置自启动和配置环境变量的方法

    1. 设置自启动 在CentOS系统下,主要有两种方法设置自己安装的程序开机启动.1.把启动程序的命令添加到/etc/rc.d/rc.local文件中,比如下面的是设置开机启动httpd. #!/bi ...

  8. centos安装eclise启动报错

    A Java Runtime Environment (JRE) or Java Development Kit (JDK) must be avail http://blog.csdn.net/u0 ...

  9. Scrum Meeting 10.23

    Scrum Meeting No.3 今天所完成的任务仍然停留在学习基础知识上.说实话,由于缺少安卓开发.web开发的经验,我们只能一步步摸索着来. 成员 已完成任务 下一阶段任务 徐越 阅读网上的博 ...

  10. OO第三阶段作业总结

    调研:        最早的程序设计是直接采用机器语言来编写的,或者使用二进制码来表示机器能够识别和执行的指令和数据.机器语言的优点在于速度快,缺点在于写起来实在是太困难了,编程效率低,可读性差,并且 ...