linux 进程调度

本文详细介绍了 Linux 内核的进程调度机制,包括不同调度策略的特点与应用场景,如 SCHED_OTHER、SCHED_FIFO 和 SCHED_RR。此外,还探讨了调度单位、优先级、时间片等关键概念。

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

<!-- /* Font Definitions */ @font-face {font-family:宋体; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-alt:SimSun; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} @font-face {font-family:"Cambria Math"; panose-1:2 4 5 3 5 4 6 3 2 4; mso-font-charset:0; mso-generic-font-family:roman; mso-font-pitch:variable; mso-font-signature:-1610611985 1107304683 0 0 159 0;} @font-face {font-family:Calibri; panose-1:2 15 5 2 2 2 4 3 2 4; mso-font-charset:0; mso-generic-font-family:swiss; mso-font-pitch:variable; mso-font-signature:-1610611985 1073750139 0 0 159 0;} @font-face {font-family:"/@宋体"; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-priority:1; mso-style-unhide:no; mso-style-qformat:yes; mso-style-parent:""; margin-top:0cm; margin-right:0cm; margin-bottom:10.0pt; margin-left:0cm; mso-pagination:widow-orphan; font-size:11.0pt; mso-bidi-font-size:10.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-fareast-font-family:宋体; mso-fareast-theme-font:minor-fareast; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi;} span.MsoPlaceholderText {mso-style-noshow:yes; mso-style-priority:99; mso-style-unhide:no; color:gray;} p.Publishwithline, li.Publishwithline, div.Publishwithline {mso-style-name:"Publish with line"; mso-style-noshow:yes; mso-style-unhide:no; mso-style-qformat:yes; mso-style-parent:""; margin:0cm; margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:16.0pt; mso-bidi-font-size:19.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-theme-font:major-latin; mso-fareast-font-family:宋体; mso-fareast-theme-font:major-fareast; mso-hansi-font-family:Calibri; mso-hansi-theme-font:major-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:major-bidi; color:#17365D; mso-themecolor:text2; mso-themeshade:191; font-weight:bold;} p.PadderBetweenControlandBody, li.PadderBetweenControlandBody, div.PadderBetweenControlandBody {mso-style-name:"Padder Between Control and Body"; mso-style-noshow:yes; mso-style-unhide:no; mso-style-next:正文; margin-top:0cm; margin-right:0cm; margin-bottom:6.0pt; margin-left:0cm; mso-pagination:widow-orphan; font-size:1.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-fareast-font-family:宋体; mso-fareast-theme-font:minor-fareast; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi;} p.underline, li.underline, div.underline {mso-style-name:underline; mso-style-noshow:yes; mso-style-unhide:no; mso-style-parent:""; margin-top:2.0pt; margin-right:0cm; margin-bottom:0cm; margin-left:0cm; margin-bottom:.0001pt; mso-pagination:widow-orphan; border:none; mso-border-bottom-alt:solid #4F81BD 1.0pt; mso-border-bottom-themecolor:accent1; padding:0cm; mso-padding-alt:0cm 0cm 2.0pt 0cm; font-size:1.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-fareast-font-family:宋体; mso-fareast-theme-font:minor-fareast; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi;} .MsoChpDefault {mso-style-type:export-only; mso-default-props:yes; font-size:11.0pt; mso-ansi-font-size:11.0pt; mso-bidi-font-size:10.0pt; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi; mso-font-kerning:0pt;} .MsoPapDefault {mso-style-type:export-only; margin-bottom:10.0pt;} /* Page Definitions */ @page {mso-page-border-surround-header:no; mso-page-border-surround-footer:no;} @page Section1 {size:595.3pt 841.9pt; margin:72.0pt 90.0pt 72.0pt 90.0pt; mso-header-margin:36.0pt; mso-footer-margin:36.0pt; mso-paper-source:0;} div.Section1 {page:Section1;} -->

[ 在此处输入文章标题 ]

 

 

进程的 sleep_avg 记录着一个进程用于休眠和用于执行的时间,范围从 0 NS_MAX_SLEEP_AVG (NS_MAX_SLEEP_AVG MAX_SLEEP_AVG 单位不同。前者一 ns 纳秒为单位,而后者以 jiffy 为单位,一般为 5ms. sleep_avg 的单位是 ns), sleep_avg 的默认值为 10ms(2 jiffy). 它的值在进程休眠 结束时根据休眠时间增大,并在进程运行时更具运行时间减小。

 

 linux 内核的三种调度方法:
1
SCHED_OTHER 分时调度策略,
2
SCHED_FIFO 实时调度策略,先到先服务
3
SCHED_RR 实时调度策略,时间片轮转 

 
实时进程将得到优先调用,实时进程根据实时优先级决定调度权值,分时进程则通过nicecounter 值决定权值,nice 越小,counter 越大,被调度的概率越大,也就是曾经使用了cpu 最少的进程将会得到优先调度。


SHCED_RR
SCHED_FIFO 的不同:

     当采用SHCED_RR 策略的进程的时间片用完,系统将重新分配时间片,并置于就绪队列尾。放在队列尾保证了所有具有相同优先级的RR 任务的调度公平。    

    SCHED_FIFO 一旦占用cpu 则一直运行。一直运行直到有更高优先级任务到达或自己放弃。

    如果有相同优先级的实时进程(根据优先级计算的调度权值是一样的)已经准备好,FIFO 时必须等待该进程主动放弃后才可以运行这个优先级相同的任务。而RR 可以让每个任务都执行一段时间。


相同点:

    RR FIFO 都只用于实时任务。

    创建时优先级大于0(1-99)

    按照可抢占优先级调度算法进行。

    就绪态的实时任务立即抢占非实时任务。


所有任务都采用linux 分时调度策略时。

1 ,创建任务指定采用分时调度策略,并指定优先级nice(-20~19)

2 ,将根据每个任务的nice 值确定在cpu 上的执行时间(counter)

3 ,如果没有等待资源,则将该任务加入到就绪队列中。

4 ,调度程序遍历就绪队列中的任务,通过对每个任务动态优先级的计算(counter+20-nice) 结果,选择计算结果最大的一个去运行,当这 个时间片用完后(counter 减至0) 或者主动放弃cpu 时,该任务将被放在就绪队列末尾( 时间片用完) 或等待队列( 因等待资源而放弃cpu) 中。

5 ,此时调度程序重复上面计算过程,转到第4 步。

6 ,当调度程序发现所有就绪任务计算所得的权值都为不大于0 时,重复第2 步。


所有任务都采用FIFO 时,

1 ,创建进程时指定采用FIFO ,并设置实时优先级rt_priority(1-99)

2, 如果没有等待资源,则将该任务加入到就绪队列中。

3 ,调度程序遍历就绪队列,根据实时优先级计算调度权值(1000+rt_priority), 选择权值最高的任务使用cpu ,该FIFO 任务将一直占有cpu 直到有优先级更高的任务就绪( 即使优先级相同也不行) 或者主动放弃( 等待资源)

4 ,调度程序发现有优先级更高的任务到达( 高优先级任务可能被中断或定时器任务唤醒,再或被当前运行的任务唤醒,等等) ,则调度程序立即在当前任务 堆栈中保存当前cpu 寄存器的所有数据,重新从高优先级任务的堆栈中加载寄存器数据到cpu ,此时高优先级的任务开始运行。重复第3 步。

5 ,如果当前任务因等待资源而主动放弃cpu 使用权,则该任务将从就绪队列中删除,加入等待队列,此时重复第3 步。


所有任务都采用RR 调度策略时

1 ,创建任务时指定调度参数为RR ,并设置任务的实时优先级和nice(nice 值将会转换为该任务的时间片的长度)

2 ,如果没有等待资源,则将该任务加入到就绪队列中。

3 ,调度程序遍历就绪队列,根据实时优先级计算调度权值(1000+rt_priority), 选择权值最高的任务使用cpu

4 ,如果就绪队列中的RR 任务时间片为0 ,则会根据nice 值设置该任务的时间片,同时将该任务放入就绪队列的末尾。重复步骤3

5 ,当前任务由于等待资源而主动退出cpu ,则其加入等待队列中。重复步骤3


系统中既有分时调度,又有时间片轮转调度和先进先出调度


1
RR 调度和FIFO 调度的进程属于实时进程,以分时调度的进程是非实时进程。

2 ,当实时进程准备就绪后,如果当前cpu 正在运行非实时进程,则实时进程立即抢占非实时进程。

3 RR 进程和FIFO 进程都采用实时优先级做为调度的权值标准,RRFIFO 的一个延伸。FIFO 时,如果两个进程的优先级一样,则这两个优先 级一样的进程具体执行哪一个是由其在队列中的位置决定的,这样导致一些不公正性( 优先级是一样的,为什么要让你一直运行?), 如果将两个优先级一样的任务 的调度策略都设为RR, 则保证了这两个任务可以循环执行,保证了公平。

2.6 Linux 3scheduling policy
#define SCHED_OTHER 0
#define SCHED_FIFO 1
#define SCHED_RR 2
第一个是普通进程的,后两个是实时进程的
一般的进程都是普通进程,系统中出现实时进程的机会很少

2.6 Linux
140 个优先级
40 个和nice value 一一对应,属于SCHED_OTHER
100 个属于SCHED_FIFO SCHED_RR
FIFO,RR
这两个的区别学过OS 应该都知道吧
一个是先进先出,一个是round robin

因为SCHED_FIFO SCHED_RR 优先级高于所有SCHED_OTHER 的进程
所以只要他们能够运行,在他们运行完之前,所有SCHED_OTHER 的进程的都没有得到执行的机会

可以以root 身份试一下这个小程序,普通用户无法调用sched_setscheduler 系统调用
不过做好准备,一但运行起来之后,要结束就只有按机箱上的reset

代码:

#include<sched.h>

#include<unistd.h>

int main(){

        struct sched_param sp;

        sp.sched_priority = 99;

        sched_setscheduler(0, SCHED_RR, &sp);

        printf("%d/n", sched_getscheduler(0));

        for(;;);

        return 0;

}

原创   linux 任务调度学习 收藏

 

调度单位

    进程描述,位于运行栈底部,可通过偏移定位

thread_info {     

         task_struct *task;   // 基本调度单位( 下面展开)

         flags //TIF_NEED_RESCHED 表明需要调度

         cpu   //CPU

        。。。

     }

任务调度的基本单位

    task_struct {    

         state   // 状态, TASK_RUNNING, ZOMBIE 或其他

         *thread_info

         prio      动态优先级

         static_prio   静态优先级

         sleep_avg    平均睡眠时间

         policy       调度算法,NORMAL, RR, FIFO

         time_slice     剩余的时间片

         rt_priority     实时优先级

         ... ...

    }

    运行队列( 调度控制结构)

    runqueue {

         task_struct *curr   正在运行的任务

         prio_array   *active   活动的优先队列

         prio_array   *expired  过期的优先队列

         prio_array   arrays[2]  实际优先队列

         ...

     }

    优先队列(O(1) 调度算法的结构)

    prio_array {

         nr_active   队列中的任务数

         bitmap[BITMAP_SIZE]  

// 优先位图, 1 表示对应优先级有进程需要调度,0 表示没有。通过位查找,快速找到优先级最高的任务。

         list_head queue[MAX_PRIO]  优先队列

    }

优先级

    linux 把进程分为实时调度与一般调度。实时调度优先级为0~99, 只用FCFSRR 来调度。非实时的一般进程优先级为100~139 ,即其计算公式为100 (最高实时优先级)+20+nice 。其中nice 值为 -20~19, 由进程创建时指定。动态优先级根据进程的交互性来动态计算优先级,一般以nice 为基数,加上-5~+5 的交互性奖罚。通过计算sleep_avg 来评估 进程的交互性,如果sleep_avg 比较多,即该进程为IO 消耗型,可把其优先级降低( 不需占用太多CPU) ,反之亦然。

时间片

    进程的可用时间片是按照计算出来的优先级按比例分配。数值为5~800ms, 默认值为100ms.

可调度标志

内核提供了一个need_resched 标志来表明是否需要重新执行一个调度。当某个进程耗尽它的时间片时,scheduler_tick() 就会设置这个标志;当一个优先级高的进程进入可执行状态的时候,try_to_wake_up() 也会设置这个标志。在返回用户空间以及从中断返回的时候,内核也会检查need_resched 标志。如果已被设置,内核会在继续执行之前调用调度程序

调度算法

    核心由schedule() 函数和scheduler_tick() 函数实现。schedule 函数从优先 级数组prio_array 中选取优先级最高的进程 --> 获取进程的thread_info --> 实施context switch 切换到新的进程运行。而scheduler_tick() 主要是更新时间片,时钟中断程序会自动调用scheduler_tick scheduler_tick 判断当前进程

若为实时进程,且时间片耗尽,重新计算时间片,并重新插入活跃队列的尾部。

若为普通进程,且时间片耗尽,重新计算时间片,移入过期队列。

    当活跃优先级队列中已没有剩余的被调度进程,活跃优先级队列与过期优先级队列的指针进行交换,进入新一轮的调度。2.6 版本内核每次时间片用完就重新计算时间片,大大提升了调度效率。

 

何时调度?(何时被调用schedule()

    1. 直接主动调用

2. 活动进程进入睡眠

3. 设置need_resched. 当从内核态返回用户态时检测这个位,如果为1 ,则调度schedule().

   以下三种情况会设置need_schedule

a. 时钟中断服务程序中,用完自己的时间片

b. 当唤醒一个睡眠进程时,该进程有更高优先级

c. 一个进程改变了调度策略,优先级等。

何时抢占?

    用户抢占

     1. 当从系统调用返回到用户态

     2. 从中断程序返回到用户态。

内核抢占

2.6 版本的内核是可以抢占的。

1. 从中断返回内核时,若内核不拥有锁,则可被抢占。若拥有锁,则不可抢占。这是内核通过preempt_count 变量来判断的。

2. 内核阻塞,导致调用schedule()

 

参考

linux kernel 2.6 进程调度分析

http://blog.163.com/steven_zyz/blog/static/1178243820071144412485/

<Linux Kernel Development 2> Robert Love

 

 

挖掘更多潜能

2.6 版本调度器的源代码都很好地封装到了 /usr/src/linux/kernel/sched.c 文件中。我们在表 1 中对在这个文件中可以找到的一些有用的函数进行了总结。

1. Linux 2.6 调度器的功能 函数名 函数说明

schedule 调度器主函数。调度优先级最高的任务执行。

load_balance 检查 CPU ,查看是否存在不均衡的情况,如果不均衡,就试图迁移任务。

effective_prio 返回任务的有效优先级(基于静态策略,但是可以包含任何奖励和惩罚)。

recalc_task_prio 根据任务的空闲时间确定对任务的奖励或惩罚。

source_load 适当地计算源 CPU (任务从中迁移出的 CPU )的负载。

target_load 公平地计算目标 CPU (任务可能迁移到的 CPU )的负载。

migration_thread CPU 之间迁移任务的高优先级的系统线程。

运行队列的结构也可以在 /usr/src/linux/kernel/sched.c 文件中找到。2.6 版本的调度器还可以提供一些统计信息(如果启用了 CONFIG_SCHEDSTATS )。这些统计信息可以从 /proc 文件系统中的 /proc/schedstat 看到,它为系统中的每个 CPU 都提供了很多数据,包括负载均衡和进程迁移的统计信息。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值