《Linux内核设计与实现》第4章读书整理
第四章 进程调度
4.1多任务
无论在单处理器或者多处理机器上,多任务操作系统都能使多个进程处于堵塞或者睡眠状态。
非抢占式多任务:除非进程自己主动停止运行,否则它会一直执行。
抢占式多任务:进程在被抢占之前能够运行的时间是预先设置好的。
4.2 Linux的进程调度
O(1)调度程序
O(1)拥有数以十计的多处理器的环境,但缺少交互进程。
4.3 策略
4.3.1 I/O消耗型和处理器消耗型的进程
I/O消耗型:大多时间在提交或等待I/O请求;
处理器消耗型:大多时间在执行代码。不属于I/O驱动类型。
4.3.2 进程优先级
相同优先级按照轮转方式进行调度。
调度程序总是选择时间片未用尽且优先级高的进程运行。
Linux两种不同的优先级范围:
nice值:-20~+19,默认0,值越大优先级越低。
实时优先级:可配置,范围0~99,值越大与优先级越大。
4.3.3 时间片
nice值作为权重将调整进程所使用的处理器时间使用比。
I/O消耗型:不需要长的时间片。
处理器消耗型:需要越长越好的时间片。
4.3.4 调度策略的活动
文字编辑程序显然是 1/0 消耗型的,因为它大部分时间都在等待用户的键盘输入〈无论用户的输入速度有多快,
都不可能赶上处理的速度λ 用户总是希望按下键系统就能马上响应。视
频编码程序是处理器消耗型的。
4.4Linux调度算法
4.4.1 调度器类
以模块方式提供的,这样做的目的是允许不同类型的进程可以有针对性地选择调度算法。
4.4.3 公平调度
使用权重;
可运行进程数量趋于无穷,每个最少也能获得 lms 的运行时间;
任何进程所获得的处理器时间是由它自己和其他所有可运行进程nice 值的相对差值决定的。
4.5Linux调度的实现
4.5.1 时间记账
所有的调度器都必须对进程运行时间做记账。
定义在kemeVsched_fair.c 文件中的 update_curr()函数实现了该记账功能。
4.5.2 进程选择
(1)挑选下一个任务
你从树的根节点沿着左边的子节点向下找,一直找到叶子节点,你便找到了其vruntime 值最小的那个进程。
(2)向树中加入进程
发生在进程变为可运行状态(被唤醒〉或者是通过fork()调用第一次创建进程时。
调用_enqueue_entity()进行繁重的插入操作,把数据项真正插入到红黑树中。
(3)从树中删除进程
发生在进程堵塞(变为不可运行态〉或者终止时(结束运行〉。
由辅助函数_dequeue_entityO 完成的。
4.5.3 调度器入口
主要入口点是函数schedule(),它定义在文件kemel/sched.c中。
4.5.4 睡眠和唤醒
内核的操作都相同 2 进程把自己标记成休眠状态,从可执行红黑树中移出,放入等待队列,然后调用 schedule()选择和执行一个其他进程。
唤醒的过程刚好相反进程被设置为可执行状态,然后再从等待队列中移到可执行红黑树中。
4.6抢占和上下文切换
4.6.1 用户抢占
在以下情况产生:
从系统调返回用户空间时;从中断处理程序返回用户空间时;
4.6.2 内核抢占
在以下情况发生:
中断处理程序正在执行,且返回内核空间之前;内核代码再一次具有可抢占性;如果内核中的任务显式地调用 schedule();
如果内核中的任务阻塞(这同样也会导敖调用 schedule()。
4.7实时调度策略
两种:SCHED_FIFO和 SCHED_RR。
4.8与调度相关的系统调用
4.8.1 与调度策略和优先级相关的系统调用
sched_setparam()和sched__getparam()分别用于设置和获取进程的实时优先级
nice()函数会调用内核的 set_ user_ nice()函数,这个函数会设置进程的 task_struct 的 static_prio 和prio 值。
4.8.2 与处理器绑定有关的系统调用
强制指定“这个进程无论如何都必须在这些处理器上运行”。