Linux内核之进程调度

来源:互联网 发布:中信期货交易软件 编辑:程序博客网 时间:2024/05/27 20:59

一些概念

  调度程序负责决定哪个进程投入运行,何时运行及运行多长时间。进程调度程序就是在可运行态进程之间分配有限的处理器时间资源的内核子系统。
多任务系统可分为两类:非抢占式多任务抢占式多任务。Linux提供了抢占式多任务。
I/O消耗型进程就是大部分时间用来提交I/O请求或者是等待I/O请求。
处理器消耗型进程就是把时间大多用在代码执行上。
调度策略通常就是在两个矛盾的目标中间寻求平衡:进程迅速响应(响应时间短)、最大系统利用率(高吞吐量)。
进程优先级:Linux中用nice值表示,范围是从-20到+19,默认为0,越大的nice值代表更低的优先级。
时间片:是进程在被抢占之前所能持续运行的时间。时间片太短会明显增加进程切换带来的处理器耗时;时间片太长会导致系统交互表现欠佳。

Linux调度算法

Linux调度器是以模块方式调度的,这样做的目的是允许不同类型的进程可以针对性的选择调度算法。
完全公平调度算法(CFS)是针对普通进程的调度,在Linux中称为SCHED_NORMAL。算法定义在文件kernel/sched_fair.c。
完全公平调度(CFS)不是直接分配时间片到进程,而是将处理器的使用比划分给进程,同时nice值(优先级)只是作为进程获得的处理器运行比的权重(几何加权)。

Linux调度的实现

CFS调度算法的实现分四个组成部分:

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

时间记账:

CFS使用调度器实体结构(struct_sched_entity)来追踪进程运行的时间记账,调度器实体结构是作为se成员变量嵌入在进程描述符struct task_struct内。
虚拟实时vruntime变量存放进程的虚拟运行时间,CFS用vruntime来记录一个程序到底运行了多长时间以及还要运行多长时间。

进程选择:

CFS调度算法的核心:选择最小的vruntime的任务。
CFS使用红黑树来组织可运行的进程队列,并利用其迅速找到最小vruntime的进程。Linux中红黑树成为rbtree,是一个自平衡二叉搜索树。红黑树是以树节点的形式存储数据,每个数据对应一个键值。
平衡二叉搜索树的原则是键值小于该节点,则转向左分支,键值大于该节点,则转向右分支。所以CFS的进程选择算法可简单总结为“运行rbtree树中最左边叶子节点所代表的进程”。
CFS将进程加入到rbtree中是发生在进程变为可运行状态或者是通过fork调用第一次创建进程时。添加原则就是键值小的走左分支,键值大的走又分支。
CFS将进程从rbtree中删除是发生在进程阻塞或者终止时。

调度器入口

进程调度的主要入口点是函数schedule():选择哪个进程可以运行,何时将其投入运行。函数会调用pick_next_task(),以优先级为序依次检查每一个调度类,从最高优先级的调度类中选择最高优先级的进程。

睡眠和唤醒

睡眠:进程把自己标记为休眠状态,从可执行红黑树中移除,放入等待队列,然后调用schedule()选择和执行一个其他进程
唤醒:唤醒操作通过wake_up()函数进行,唤醒指定的队列的所有进程。

抢占和上下文切换

上下文切换就是从一个可执行进程切换到另一个可执行进程,由context_switch()函数负责处理。
用户抢占:内核即将返回用户空间的时候,如果need_resched标志被设置,会导致schedule()被调用。用户抢占发生在以下情况,从系统调用返回用户空间时;从中断处理程序返回用户空间时。
内核抢占:Linux支持完整的内核抢占,只要没有锁,内核就可以进行抢占。
内核抢占发生在:
- 中断处理程序正在执行,且返回内核空间之前
- 内核代码再一次具有可抢占性的时候
- 内核中的任务显式的调用schedule
- 如果内核中的任务阻塞

实时调度策略

Linux提供了两种实时调度策略:SCHED_FIFOSCHED_RR
SCHED_FIFO实现的是一种简单的、先入先出的调度算法,不使用时间片。处于可运行状态的SCHED_FIFO级进程会比任何SCHED_NORMAL级的进程优先得到调用。它不基于时间片,可以一直执行下去,只有自己收阻塞或者显式的释放处理器,或者更高优先级的SCHED_FIFO或SCHED_RR进程抢占。相同优先级的SCHED_FIFO进程会轮流执行,但同样是在它们愿意让出处理器才行。
SCHED_RR是带有时间片的SCHED_FIFO,这是一种实时轮流调度算法。

0 0
原创粉丝点击