调度的基本概念


一.调度的基本概念

1.时间片:进程在被抢占前预先设置好占用处理器的时间段。默认时间片时间为10ms,linux的CFS(完全公平调度算法)并没有直接使用时间片分配给进程,它是将处理器的使用比划分给进程。
2.多任务操作系统分为抢占式和非抢占式。抢占式会被强制挂起,非抢占式只能自己主动停止,否则一直执行。linux系统是抢占式是系统。

二.调度程序设计的基础

1.i/o消耗性进程:大部分时间用来提交I/o请求,或者等待i/o请求。例如键盘输入或者网络i/o。
2.处理器消耗性进程:把时间主要用在程序执行上,调度策略一般是尽量降低他们的调度频率,而延长运行时间。如MATLAB
3.进程优先级:根据进程的价值和对时间的需求来对进程分级的想法。Linux有二种优先级范围,第一种是nice值,范围为-20
到19,默认为0,越大的nice意味着优先级越低,可以通过ps -el命令查看系统中的进程列表,结果中NI的一列就是进程的nice。
4.第二种为实时优先级,其值可配置,范围为0-99.数值越大优先级越高。

三.linux调度算法

1.公平调度:CFS(完全公平调度算法)的出发点基于一个简单的理念,进程调度的效果应如同系统具备一个理想多任务处理器,在这种系统中,每个进程将能获得1/n的处理器时间-n指可运行进程的数量,这种属于理想化的模型。实际中CFS的做法是允许每个进程运行一段时间、循环轮转、选择运行最少的进程作为下一个运行进程,而不采用分配每个进程时间片的说法。nice在CFS中被作为获取处理器运行比的权重。
2.最小粒度:CFS为每个进程获得的时间片底线,默认为1ms。
3.总结:任何进程所获取的处理器时间是由他自己和其他所有进程nice值的相对差值决定的。

四.linux调度的实现

1.时间记账

所有的调度器必须对进程的运行时间进行记账,CFS不再具有时间片的概念,但是他必须维护每个进程的运行时间,因为他需要确保每个进程只在公平分配给她的处理器时间内运行。
    a.CFS使用调度实体结构来追踪进程运行记账,调度器的实体结构作为一个名为se的的成员变量嵌入在进程描述符struct task_struct中。
    b.虚拟时间:vruntime变量是用来存放进程的虚拟运行时间,该运行时间的计算时经过所有可运行进程总数的标准化(或者说时被加权的)。通常以ns为单位。CFS使用vruntime来记录一个程序到底运行多长时间,以及他还应该再运行多长时间。
    时间记录的具体实现:update_curr()计算了当前进程的执行时间,将其存放在delta_exec变量中。然后他又将运行时间传递给了_update_curr(),由后者再根据当前运行进程总数对运行时间进行加权计算。最终将上述的权重值与当前运行进程的vruntime相加。由于update_curr是由系统定时器周期调用的,无论是在进程处于可运行状态还是被堵塞处于不可运行状态,根据这种方式,vruntime可以准确的测量给定进程的运行时间,而且还可以知道谁将是下一个被运行的进程。

2.进程选择


 a.CFS的核心思想是选择具有最小vruntime的进程作为下一个运行的进程
    b.CFS使用红黑树来组织可运行的进程队列,并利用其迅速找到最小vruntime的进程。
    c.挑选下一个任务:红黑树存储了所有进程的,其中节点的键值便是可运行程序的虚拟运行时间。因此根据红黑树的特点。键值最小的是红黑树最左边的叶子。因此,CFS算法可以总结为:运行红黑树中最左边叶子节点所代表的那个进程。
    d.所以进程进入可运行状态,就是将该进程加入红黑树,同理,当进程堵塞或者终止时,通过从红黑树中删除进程。


3.调度入口


    a.进程调度的主要入口点是:函数schedule()。选择那个进程可运行,何时将其投入运行。
    b.上面函数唯一重要的事是:调用pick_next_task()函数,他会依照优先级的高低,从高到低,依次检查每一个调度类,并且从最高优先级调度类中选择最高优先级的进程。
    c.每个调度类都会实现pick_next_task()函数,他会指向下一个会执行的进程,或者没有时返回NULL。


4.睡眠和唤醒


    a.进程把自己标成休眠状态,从执行红黑树中移除,放入等待队列,然后调用schedule()选择和执行一个其他进程。唤醒恰好相反:进程被设为可执行状态,然后再从等待 队列中移除到可执行红黑树中。
    b.等待队列:是由等待某些事件发生的进程组成的简单链表。


5.抢占和上下文切换

就是从一个可执行进程切换到另一个可执行进程。
    a.每当一个进程被选中准备投入运行的时候,schedule()就会调用context_switch()函数。他主要完成以下二项基本任务:
      1)调度switch_mm(),该函数复制吧虚拟内存从上一个进程映射到新进程中。
      2)调度switch_to(),该函数负责从上一个进程的处理器状态切换到新进程的处理器状态。
    b.内核是怎么知道什么时候调用schedule()。内核提供了一个need_resched标志表明是否需要重新执行一次调度。
    c.用户抢占:内核即将返回用户空间的时候,如果need_resched被设置,会导致schedule()被调用,此时就会发生用户抢占。用户抢占的情形:
      1)从系统调用返回用户空间时。
      2)从中断处理程序返回用户空间时。
    d.内核抢占:只要重新调度是安全的,内核就可以在任何时间抢占正在执行的任务。何时安全?只要没有锁,内核就可以进行抢占,锁是非抢占区域的标志。为了支持内核抢占,就为每个进程的thread_info引入preempt_count计数器。计数器初始值为0,每当使用锁就加1,释放锁就减1.当值为0时,内核就可以被强占。
      1)内核抢占的的条件:中断返回内核空间时,内核会检查preempt_count和need_resched,如果前者值为0.后者被设置,则会发生内核抢占。
      2)内核抢占的情况:
            中断处理程序正在执行,且返回内核空间之前;
            内核代码再一次具有可抢占性的时候;
            如果内核中的任务显示的调用了schedule();
            如果内核中的任务堵塞(同样会导致调用schedule())。


6.实时调度策略:SCHED_FIFO和SCHED_RR


    a.SCHED_FIFO策略是一种简单的先进先出的调度算法。它不使用时间片,可以一直执行下去。
    b.SCHED_RR是带有时间片的SCHED_FIFO策略,是一种实时调度轮换策略。时间片是用来重新调度同一优先级的进程的。

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值