[笔记分享] [OS] Linux的进程调度

本文介绍了Linux的进程调度,包括其可抢占的多任务模式、调度策略、调度算法以及抢占和上下文切换的过程。讲解了nice值、实时优先级、时间片的概念,并详细阐述了O(1)调度算法的工作原理,以及如何在内核层面实现抢占和上下文切换。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Platform: msm8x60
Kernel: 2.6

介绍

多任务操作系统都可以让程序的并发执行,这种功能通过进程调度来实现。Linux提供了抢占式的多任务模式,由调度程序决定什么时候可以被抢占。


策略

进程分I/O消耗和处理器消耗型两种。I/O消耗型如键盘活动,处理器消耗型如视频解码。调度策略采用复杂的算法来决定哪个进程投入运行。一般都倾向于I/O消耗型进程。

优先级有两种:
1. nice值。范围-20到 +19,默认为0, 值越大优先级越低,它也用来决定时间片的长短。
2. 实时优先级。可配置,默认范围从0到99。任何实时进程优先级都高于普通进程。

再来说下时间片,它表明的是一个进程在被抢占前所能运行的时间。进程并不是一次用完它的时间片。没有时间片的进程不会再投入运行,等其他所有进程全部耗尽时间片后,再重新分配。

Linux是可抢占式的。当一个进程进入TASK_RUNNING时,内核先判断其优先级是否高于其他进程,如果是,调用程序被唤醒,抢占当前进程。当进程时间片变为0时,也会被抢占。


调度算法

Linux2.6以O(1)调度为核心算法,调度的时间是恒定的,保证了对各个进程之间的公平性。
最基本数据结构为运行队列。每个处理器一个,每个可投入运行的进程属于一个运行队列。通过cpu_rq()、this_rq()、task_rq()等宏来获取可执行队列,对多个运行队列操作时为避免死锁可通过double_rq_lock()、double_rq_unlock()来自动完成防死锁操作。
每个运行队列有两个优先级数组,过期和活跃数组。结构如下:

struct prio_array{
    Int nr_active;
Unsigned long bitmap[BITMAP_SIZE];
struct list_head queue[MAX_PRIO];
};

queue表示可执行或者过期进程链表,最大为MAX_PRIO,bitmap为每个优先级的映射,nr_nr_active标志链表上有多少个进程。

原理如下: 当某个进程准备执行时,将bitmap某位置1,这样查找相应bitmap的某位是否为1就可以了,查找时间恒定。因此我们调用schedule()时间也是恒定的。
对时间片重新计算也是很快的,原理如下:

当一个进程时间片耗尽时,被移到过期数组,当全部进程时间片都用完后。只要将过期数组和活动数组通过指针相互对调就可以了。


抢占和上下文切换

抢占时,schedule()完成两项基本工作:
1. 通过switch_mm()把虚拟内存从前一个进程切换到新进程中区。
2. 通过switch_to()从前一个进程的处理器状态切换到新进程中区。包括保存、恢复站信息和寄存器信息。

内核提供一个need_resched标志来表明是否需要重新调度。当进程时间片耗尽时,scheduler_tick()会设置它;当一个优先级更高的进程进入可执行状态时,try_to_wake_up()会设置它。

在返回用户空间及中断返回时,内核会检查这个标志,如果被设置,内核会继续调用调度程序。
用户抢占发生情况:
1. 从系统调用返回用户空间
2. 从中断处理程序返回用户空间

内核也可被抢占,标志是preempt_count。当其为0时,可以抢占,否则不行。当从中断返回内核空间时,内核会检查need_resched和preempt_count标志。如果need_resched被设置而且preempt_count为0时,进行调度。如果preempt_count不为0,而need_reshced被设置,那么等当前内核进程执行完后再检查need_resched标志来决定是否调度。

内核抢占发生情况:
1. 从中断程序返回内核空间
2. 显示调用
3. 进程睡眠

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值