第八周读书笔记

第四章 进程调度

1、多任务

1.非抢占式多任务

进程会一直执行直到本身主动中止运行(这一步骤称为让步)linux

2.抢占式多任务

Linux/Unix使用的是抢占式的方式;强制的挂起进程的动做就叫作抢占。进程在被抢占以前可以运行的时间是预先设置好的(也就是进程的时间片)算法

2、策略

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

(1)进程分为I/O消耗型和处理器消耗型函数

  • I/O消耗型:进程的大部分时间用来提交I/O请求或是等待I/O请求。这样的进程常常处于可运行状态,但一般是短短一下子。由于它在等待更多的I/O请求时最后总会阻塞。ui

  • 处理器消耗型:把时间大多用在执行代码上。除非被抢占,不然一直不停地运行。对于这类,调度策略尽可能下降他们的调度频率,而延长其运行时间。spa

(2)调度策略一般在两个矛盾的目标中间寻找平衡:进程响应迅速(响应时间短)和最大系统利用率(高吞吐量)。unix

(3)Unix系统更倾向于I/O消耗型程序,以提供更好的程序响应速度。队列

2. 进程优先级

在某些系统中,优先级高的进程使用的时间片也比较长。调度程序老是选择时间片未用尽并且优先级最高的进程运行。用户和系统均可以经过设置进程的优先级来影响系统的调度。进程

Linux采用了两种不一样的优先级范围——nice值和实时优先级值。事件

(1) nice值,范围是-20到19,数值越大优先级越低,默认值为0。Linux中,nice值则表明时间片的比例。能够经过ps-el命令查看系统中的进程列表,结果中标记NI的一列就是进程对应的nice值。内存

(2) 实时优先级值,默认0到99,数值越大优先级越高。任何实时进程的优先级都高于普通的进程。
查看进程列表以及对应的实时优先级:ps-eo state,uid,pid,ppid,rtprio,time,comm.

3.时间片

代表进程被抢占前所能持续运行的时间。长时间片致使系统交互表现欠佳。

(1)Linux的CFS调度器:没有直接分配时间片到进程,而是将处理器的使用比划分给进程。其抢占时机取决于新的可运行程序消耗了多少处理器使用比。若是消耗的使用比比当前进程小,马上投入运行,抢占当前进程;不然推迟运行。

3、Linux调度算法

1.调度器类

(1)Linux调度器是以模块方式提供的(也就是调度器类),目的是容许不一样类型的进程能够有针对性地选择调度算法

(2)调度器类容许多种不一样的可动态添加的调度算法并存,调度属于本身范畴的进程;

(3)调度器代码会按照优先级顺序遍历调度类,拥有一个可执行进程的最高优先级的调度器类胜出,去选择下面要执行的那一个程序;

2.Unix中系统调度问题

(1)将nice值映射到时间片的话,就必须将nice值对应处处理器的绝对时间;这样会致使进程切换没法最优进行;

(2)若是使用相对nice值,所带来的效果将会极大取决于其nice的初始值;

(3)若是执行nice值到时间片的映射,时间片极大受制于定时器。

3.公平调度

  • 目标延迟:CFS为完美多任务中的无限小调度周期的近似值设立的一个目标。越小的调度周期将带来越好的交互性,同时也更接近完美的多任务。但必须承受更高的切换代价和更差的系统总吞吐能力。

  • 最小粒度:CFS引人每一个进程得到的时间片底线,这个底线称为最小粒度。

CFS中,任何进程所得到的处理器时间是由它本身和其余全部可运行进程nice值的相对差值决定。任何nice值对应的绝对时间是处理器的使用比。

4、Linux调度的实现

1.时间记帐

  • 全部的调度器都必须对进程的运行时间作记帐;
  • CFS使用调度器实体结构来追踪运行记帐

2.虚拟实时

  • vrntime变量【也就是在上面所说的实体结构中】存放虚拟运行时间。虚拟时间以ns为单位,和节拍定时器无关;
  • update_curr()函数实现了记帐功能;计算了当前进程的执行时间并将其存放在data_exec中;而后将运行时间传递给了_update_curr(),由后者再根据当前可运行进程总数对运行时间进行计算,最终肯定上述的权重值与当前运行进程的vrntime。

3.进程选择

(1)CFS算法核心:选择具备最小vrntime的任务

(2)具体作法:利用红黑树rbtree(以节点形式存储数据的二叉树)

4.进程调度入口

(1)进程调度的主要入口点是函数schedule(),定义在kernel/sched.c中;这正是内和其余部分用于调度进程调度器的入口

(2)这一函数最重要的工做就是调用pick_next_state(),依次检查每个调度类,并从最高优先级的调度类中,选择最高优先级进程

5.睡眠和唤醒

(1)进程休眠必定是为了等待一些事件

  • 进程把本身标记成休眠状态,从可执行红黑树中移除;
  • 放入等待队列——由等待某些时间发生的进程组成的链表,内核用wake_queue_head_t来表明等待队列

(2)唤醒操做由函数wake_up()进行

  • 它会调用函数try_to _wake_up()将进程设置为TASK_RUNNING状态,调用enqueue_task()将进程放入红黑树中
  • 固然,也存在虚假唤醒进程的状态

5、抢占和上下文切换

上下文切换由定义在kernel/sched.c中的context_switch()函数负责,每当一个新的进程被选出来准备运行的时候,schedule()就会调用该函数:

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

1.用户抢占

发生时机:

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

2.Linux系统支持内核抢占

(1)只要没有锁,内核就能够进程抢占;

(2)为了支持抢占,每一个进程的thread_info都加入了preempt_count计数器(初值为0,每当使用锁的时候就加1,释放锁的时候数值减1),当数值为0时,内核就能够抢占

(3)内核抢占发生在:

  1. 中断处理程序正在执行且返回内核空间以前;
  2. 内核代码再一次具备可抢占性的时候;
  3. 内核中的任务显式地调用schedule函数

6、实时调度策略

  • linux 提供两种实时调度策略SCHED_FIFO和SCHED_RR。

  • SCHED_FIFO实现了一种简单的、先入先出的调度算法:它不使用时间片.处于可运行状态的SCHED_FIFO 级的进程会比任何SCHED_NORMAL 级的进程都先获得调度。
  • SCHED_RR级的进程在耗尽事先分配给它的时间后就不能再继续执行了.即 SC阻止RR 是带有时闹片的SCHED_FIFO-这是一种实时轮流调度算挂。
相关文章
相关标签/搜索