从上帝视角看OS进程调度

 

下面所属以Linux 1.1.0源码为例(Linux初期版本,源码1w多行,推荐阅读源码,或看相关书籍 Linux内核(v1.2.0)注释

 

相关部件:

Linux OS

CPU:有自己的频率,通常很高(如笔者当前机器的CPU频率为1.3GHZ,即其寄存器的操作延迟为0.8ns左右),因此可以在1秒内做非常多的事。

可编程定时器/计数器Timer:有自己的频率,Linux源码中定为100,即 10ms 触发一次。OS内的很多时间计数以此为单位,如OS滴答数的单位、进程调度的时间片的单位都是Timer的周期。

背景:

进程是OS资源分配的基本单位、线程是CPU调度的基本单位。但在Linux内核中实际上没有线程概念,我们所说的线程在Linux内核中是轻量级进程LWP,其数据就结构表示与进程一样,从这角度看,内核中就是进程(或称任务)调度。

OS进程调度就是OS选择一个进程让它获得CPU执行权的过程。进程获得CPU执行权后就可以执行其代码了,但不是无限执行——会由OS设置一个可执行时长(称为时间片或时间计数器),通常是Timer周期的倍数。

CPU收到中断请求时会从固定的地址去查找中断向量表,并根据中断请求号从表中取得对应的中断处理函数执行。

对于不同的OS,中断向量表内容、同一个中断号对应的中断处理函数都可能不同,这些是在由OS在初始化时设置的。如(sched.c): set_intr_gate(0x20, &timer_interrupt); 。

进程调度的原理概要:

Timer 每次触发时向CPU发出时间中断请求:10ms一次,中断号为20。

CPU响应时间中断请求:找到该中断号对应的中断处理函数 timer_interrupt 并执行。

该函数逻辑:若当前在执行的进程的时间片未用完则进程继续执行且时间片减1,否则调用函数 sched.c 进行进程调度。

后者的逻辑:从所有RUNNABLE状态的进程中选择时间片counter最大者(若值都为0则包括非RUNNABLE的所有进程的counter重新赋值 counter = counter/2 + priority,然后重新选进程),切换(类似于函数调用,从CPU寄存器获取当前进程上下文信息并保存到内存栈,新进程上下文信息设置到CPU寄存器即可)到该进程执。

可见,进程调度的始驱动力就是Timer,OS巧妙地利用了Timer、CPU、时间中断来定期地进行进程调度,这个“定期”就是Timer的周期长。

上述过程是在v1.1.0源码中的原理,如今版本可能已经差别较大,但原理相通。万变不离其宗。

 

 

详情推荐参阅:上帝视角看进程调度—公众号地并发编程Linux内核(v1.2.0)注释

 

从上帝视角看OS进程调度

上一篇:关于Objective-C和C++中的继承及其区别


下一篇:Linux内核最新版和内核升级