《Linux内核设计与实现》读书笔记(二)--进程调度

来源:互联网 发布:sybase数据库导出mdb 编辑:程序博客网 时间:2024/05/16 12:42

  本章讨论进程调度程序,它是确保进程有效工作的一个内核子系统。进程调度程序可看做在可运行状态进程之间分配有限的处理器时间资源的内核子系统。

1、多任务

  多任务操作系统就是能同时并发地交互执行多个进程的操作系统。
  多任务系统可划分为两类:非抢占式多任务和抢占式多任务。
  抢占式多任务模式下,由调度程序来决定什么时候停止一个进程的运行,以便其他进程能够得到执行机会,这个强制的挂起动作就叫做抢占。
  进程在被抢占之前能够运行的时间是预先设置好的,叫做进程的时间片。时间片是分配给每个可运行进程的处理器时间段。
  非抢占式多任务模式下,除非进程自己主动停止运行,否则他会一直执行。进程主动挂起自己的操作成为让步

2、策略

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

  进程可被分为I/O消耗型和处理器消耗型。前者指进程的大部分时间用来提交I/O请求或是等待I/O请求;处理器消耗型把时间大多用在执行代码上。
  调度策略通常要在两个矛盾的目标中寻找平衡:进程响应迅速(响应时间短)和最大系统利用率(高吞吐量)。
#

2.2 进程优先级

  基于优先级的调度:根据进程的价值和其对处理器时间的需求来对进程分级的想法。
  Linux采用了两种不同的优先级范围。
  第一种是使用nice值。范围从-20到+19,默认值为0。越大的nice值意味着更低的优先级。
  第二种范围是实时优先级,其值是可配置的。默认情况下它的变化范围是从0到99。与nice相反,越高的实时优先级述职意味着优先级越高。任何实时进程的优先级都高于普通的进程。

2.3 时间片

  时间片是一个数值,它表示进程在被抢占前所能持续运行的时间。
  调度策略是一个平衡的过程:时间片过长会导致系统对交互的相应表现欠佳,让人觉得系统无法并发执行应用程序;时间片太短会明显增大进程切换带来的处理器耗时。

3、Linux调度算法

完全公平调度算法(CFS)

  调度的原理,实际的调度算法虽然不会这么简单,但是基本的实现原理也是类似的:
  1. 确定每个进程能占用多少CPU时间(这里确定CPU时间的算法有很多,根据不同的需求会不一样);
  2. 占用CPU时间多的先运行;
  3. 运行完后,扣除运行进程的CPU时间,再回到 1);

3.1 时间记账

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

    struct_sched_entity;    /*调度器实体结构*/

  vruntime变量存放进程的虚拟运行时间,该运行时间的计算经过了所有课运行进程总数的标准化。以ns为单位。
  update_curr()计算了当前进程的执行时间,并且将其存放在变量delta_exec中。然后它又将运行时间传递给了__update_curr(),由后者在根据当前可运行进程总数对运行时间进行加权计算。最终将上述的权重值与当前运行进程的vruntime相加。
  update_curr()是由系统定时器周期性调用的,无论是在进程处于可运行态,还是被堵塞处于不可运行态。根据这种方式,vruntime可以准确地测量给定进程的运行时间,且可知道谁应该是下一个被运行的进程。

3.2 进程选择

  CFS调度算法的核心:选择具有较小vruntime的任务运行。
  CFS使用红黑树来组织可运行进程队列,并利用其迅速找到最小vruntime值的进程。红黑树:rbtree,是一个自平衡二叉搜索树。

3.3 调度器入口

  进程调度的入口函数是schedule(),它是内核其他部分用于调用进程调度器的入口:选择哪个进程可以运行,何时将其投入运行。
  schedule()函数会调用pick_next_task(),该函数会以优先级为序,从高到低,依次检查每一个调度类,并且从最高优先级的调度类中,选择最高优先级的进程。

3.4 睡眠和唤醒

  休眠的进程处于一个特殊的不可执行的状态。
  休眠:进程把自己标记为休眠状态,从可执行红黑树中移除,放入等待队列,然后调用schedule()选择和执行一个其他进程。
  唤醒:进程被设置为可执行状态,然后再从等待队列中移到可执行红黑树中。

4、抢占和上下文切换

  上下文切换,指的是从一个可执行进程切换到另一个可执行进程,由context_switch()函数完成。
  用户抢占在以下情况产生:

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

  内核抢占:只要没有持有锁,内核就可以抢占正在执行的任务。锁是非抢占区域的标志。会发生在以下情况:

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

5、与调度相关的系统调用

系统调用 描述 nice() 设置进程的nice值 sched_setscheduler() 设置进程的调度策略,即设置进程采取何种调度算法 sched_getscheduler() 获取进程的调度算法 sched_setparam() 设置进程的实时优先级 sched_getparam() 获取进程的实时优先级 sched_get_priority_max() 获取实时优先级的最大值,由于用户权限的问题,非root用户并不能设置实时优先级为99 sched_get_priority_min() 获取实时优先级的最小值,理由与上面类似 sched_rr_get_interval() 获取进程的时间片 sched_setaffinity() 设置进程的处理亲和力, sched_getaffinity() 获取进程的处理亲和力 sched_yield() 暂时让出处理器
阅读全文
0 0
原创粉丝点击