Linux进程调度和内核同步

一、什么叫进程调度?

决定哪个进程投入运行,什么时候运行,运行多久,就叫进程调度。实现这样功能的程序,叫进程调度程序。

二、目的:

在进程快速响应和系统最大利用率之间寻找平衡。

例如I/O消耗型进程需要在键盘等I/O设备产生硬件中断时快速响应,其他时间不消耗处理器,大部分在等待。

而处理器消耗型进程,要占着CPU,例如视频播放器。

三、时间片的概念:

在进程被抢占之前,所能持续运行的时间。

时间片不能太短,否则显得进程调度反而消耗处理器的时间更长;

时间片不能太长,否则显得系统交互性能太差。

四、两种类型的进程:

普通进程和实时进程

普通进程的调度算法是CFS(完全公平调度算法),称为SCHED_NORMAL;该算法不是直接分配时间片到进程,而是将处理器的使用比划分给进程,同时nice值(取值范围-20~19)只是作为进程获得的处理器运行比的权重。

针对实时进程,有两种调度策略,SCHED_FIFOSCHED_RR,暂不详细讲解。

五、CFS算法实现:

时间记账:CFS用vruntime来实时跟踪记录一个进程运行了多少时间,还要运行多少时间;

进程选择:利用红黑树查找vruntime最小的进程(最左叶子节点)。CFS将进程加入到rbtree中是发生在进程变为可运行状态或者是通过fork调用第一次创建进程时;将进程从rbtree中删除是发生在进程阻塞或者终止时。

调度器入口:schedule()函数。以优先级为序依次检查每一个调度类,从最高优先级的调度类中选择最高优先级的进程。

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

六、内核抢占和上下文切换:

上下文切换:由context_switch()函数负责。

用户抢占:内核即将返回用户空间的时候,如果need_resched标志被设置,会导致schedule()被调用。用户抢占发生在以下情况,从系统调用返回用户空间时;从中断处理程序返回用户空间时。

内核抢占:Linux2.6开始支持内核抢占。内核抢占发生在:
- 中断处理程序正在执行,且返回内核空间之前
- 内核代码再一次具有可抢占性的时候
- 内核中的任务显式的调用schedule
- 内核中的任务阻塞时

七、内核同步:

在内核抢占和进程调度时,同一资源存在访问过程被打断,或者在打断和重新执行期间,被另一个进程访问的风险,如果没有内核同步技术,将得到意料之外的结果。

考虑内核同步时需要了解几个内核约束场景:

(1)同一个tasklet不可能同时在几个CPU上执行。——所以仅被一种tasklet访问的数据结构不需要同步。

(2)软中断和tasklet不能在一个给定的CPU上交错执行。——所以仅被软中断和tasklet访问的每CPU变量不需要同步。

(3)中断ISR、软中断和tasklet既不可以被抢占也不能被阻塞。在最坏情况下,它们的执行将有轻微的延迟,因为在其执行的过程中可能发生其他的中断(内核控制路径的嵌套执行)。执行中断处理的内核控制路径不能被执行可延迟函数或系统调用服务例程的内核控制路径中断。

同步技术有哪些?

(1)每CPU变量:主要是数据结构数组,每个CPU对应数组的一个元素。

(2)原子操作:原子的“读——修改——写”。

(3)自旋锁:加锁时忙等。一直旋转,等待锁释放,不会休眠。不可递归。

(4)信号量:加锁时阻塞等待(睡眠)。发现别人占用锁后就休眠自己,别人释放后就唤醒自己。
(5)顺序锁:基于访问计数器的锁。

(6)内存屏障:避免指令重新排序。

猜你喜欢

转载自blog.csdn.net/u011306659/article/details/81181050