前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >图解Linux进程调度(二)

图解Linux进程调度(二)

作者头像
用户6280468
发布于 2022-06-09 13:24:35
发布于 2022-06-09 13:24:35
1.7K00
代码可运行
举报
文章被收录于专栏:txp玩Linuxtxp玩Linux
运行总次数:0
代码可运行

优先级与调度策略:

在内核中,肯定不能对所有的进程一视同仁,有的进程需要优先运行,有的进程需要运行更长的时间

为了更好地实现进程调度,每个进程都有自己的优先级和调度策略

所谓优先级,就是表示这个进程的重要性,优先级高的自然会被更好的对待

那调度策略又是什么呢?想一想,进程调度其实是一个非常复杂的问题,想使用一种算法来实现良好的进程调度是不可能的,Linux内核实现了好几种调度算法。所谓调度策略,你可以理解为使用哪种算法来管理进程

每个进程都使用 task_struct 结构来表示,在这个结构体中,关于调度策略的定义如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
unsigned int policy;

policy 表示该进程采用哪种调度策略,内核提供了以下几种调度策略policy 表示该进程采用哪种调度策略,内核提供了以下几种调度策略:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#define SCHED_NORMAL  0
#define SCHED_FIFO  1
#define SCHED_RR  2
#define SCHED_BATCH  3
#define SCHED_IDLE  5
#define SCHED_DEADLINE  6

Linux内核的进程大概可分为两类,一类是普通进程,一类是实时进程

其中属于实时进程的调度策略是:

  • SCHED_FIFO
  • SCHED_RR
  • SCHED_DEADLINE

属于普通进程的调度策略是:

  • SCHED_NORMAL
  • SCHED_BATCH
  • SCHED_IDLE

下面我来跟你详细讲解每个调度策略代表什么:

  • SCHED_DEADLINE:这是实时进程的调度策略,它是按照任务的deadline来调度的,当产生一个调度点的时候,总会选取距离deadline最近的进程来运行
  • SCHED_FIFO:这是实时进程的一种调度策略,FIFO表示先进先出机制,在使用该调度策略的进程被选中运行后,它可以运行任意长时间,直到更高优先级的进程抢占或者自己让出CPU
  • SCHED_RR:这也是实时进程的调度策略,RR是时间片轮转调度,每个使用该调度策略的进程都有自己的时间片,进程运行直到时间片耗尽,再将其添加到运行队列尾部,如此循环
  • SCHED_NORMAL:表示普通进程的调度策略,内核大多数进程都属于普通进程,普通进程使用完全公平调度算法实现调度
  • SCHED_BATCH:是用于非交互,CPU使用密集的批处理进程,它和普通进程都是使用完全公平调度算法来实现。内核中在某时刻可以去唤醒某个进程,如果这个进程的调度策略是SCHED_BATCH,那它就不会去抢占当前正在运行的进程
  • SCHED_IDLE:是用于特别空闲的进程使用的调度策略

讲完调度策略,我们来将优先级

task_struct 中关于优先级的定义如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int prio, static_prio, normal_prio;
unsigned int rt_priority;
  • 是的,内核使用了四个变量来表示优先级,这四个变量之间的关系相当复杂,不过没关系,我会尽量地解释清楚:
  • prio:动态优先级,进程调度中判断一个进程的优先级都是使用此变量
  • normal_prio:这个变量也表示动态优先级,它表示正常的优先级。最初的时候 prio 是等于 normal_prio 的,只不过有的时候进程的优先级需要临时改变,所以会改变prio,但是 normal_prio 是不会变的。在创建子进程的时候,子进程继承的优先级是normal_prio,而不是prio
  • static_prio:表示进程优先级,进程启动的时候赋值的,内核不会去改变它,只能用户通过nice和sched_setscheduler 系统调用来设置
  • rt_priority:只有实时进程才会用到的优先级,其值范围是0~99,最低优先级是0,最高优先级是99

这四个变量有什么联系呢?

prio 和 normal_prio 最初的值是相等的,它们都是基于 static_prio 或者 rt_priority 计算的(至于基于 staticc_prio 还是 rt_priority,取决于调度策略)

下面来看一看内核的代码

内核中将0139的优先级划分为两个范围,099表示实时进程优先级,100~139的优先级表示普通进程的优先级,数值越小表示优先级越高:

首先我们讲static_prio,进程启动的时候会设置好静态优先级。如果需要修改,可以通过nice系统调用来设置,nice的范围是-2019,最终映射到优先级为100139的部分,如下所示:

内核中定义如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

/* nice的范围 */
#define MAX_NICE 19
#define MIN_NICE -20
#define NICE_WIDTH (MAX_NICE - MIN_NICE + 1) //20

#define DEFAULT_PRIO  (MAX_RT_PRIO + NICE_WIDTH / 2) //120

#define NICE_TO_PRIO(nice) ((nice) + DEFAULT_PRIO) //100~139

void set_user_nice(struct task_struct *p, long nice)
{
    ...
    p->static_prio = NICE_TO_PRIO(nice);
 ...
}

而 rt_priority 动态优先级又是怎么指定的呢?

用户层可以通过 sched_setscheduler,将普通进程更改为实时进程,通过更改进程的调度策略,同时设置 rt_priority,也就是说它的值可以是应用程序指定的,范围是0~99

在清楚 static_prio 和 rt_priority 怎么得来之后,我们来看看 normal_prio 和 prio 这两个变量是怎么计算的

内核中通过下面的代码来设置:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
p->prio = effective_prio(p);

看一下 effective_prio 的定义:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
static int effective_prio(struct task_struct *p)
{
 p->normal_prio = normal_prio(p);

 if (!rt_prio(p->prio))
  return p->normal_prio;

    /* 如果进程的优先级本来是实时优先级或者进程被提高到实时进程,那么就保持不变 */
    return p->prio;
}

可以看到,通过这条指令 p->prio = effective_prio§,会同时设置 prio 和 normal_prio,下面来看看 normal_prio 函数的定义,这个函数也是解开这几个变量之间关系的关键:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#define MAX_DL_PRIO  0

static inline int normal_prio(struct task_struct *p)
{
 int prio;

 if (task_has_dl_policy(p)) //deadline调度策略
  prio = MAX_DL_PRIO-1; //-1
 else if (task_has_rt_policy(p)) //FIFO或者RR的调度策略
  prio = MAX_RT_PRIO-1 - p->rt_priority; //99-rt_priority
 else //普通进程调度策略(NORMAL、BATCH、IDLE)
  prio = __normal_prio(p);
 return prio;
}

normal_prio 根据进程不同的调度策略,使用不同的方法来设置进程的优先级:

  • 如果进程采用 SCHED_DEADLINE 调度策略,那么优先级就等于-1,这可不在正常的0~139范围内,可见SCHED_DEADLINE 调度策略的优先级是极高的。
  • 如果进程采用 SCHED_FIFO 或者 SCHED_RR 调度策略,那么优先级就等于 99 - rt_priority,rt_priority 的范围是0~99。当rt_priority 的越大,优先级数值越小,优先级就越高。这也就是为什么动态优先级 rt_priority 越大,优先级越大。
  • 如果是采用 SCHED_NORMAL、SCHED_BATCH、SCHED_IDLE 调度策略,那么就采用 __normal_prio 来计算,其定义如下
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
static inline int __normal_prio(struct task_struct *p)
{
    /* 直接返回static_prio */
 return p->static_prio;
}

将上述的关系整理下表:

优先级和调度策略都存在于 task_struct 中,它们都是描述进程的信息,它们具体有什么用,我们下面将会介绍。

文章参考:https://blog.csdn.net/weixin_42462202/article/details/102887008?spm=1001.2014.3001.5502

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-05-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 txp玩Linux 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Linux进程优先级的处理--Linux进程的管理与调度(二十二)
从0~99的范围专供实时进程使用, nice的值[-20,19]则映射到范围100~139
233333
2018/12/10
3.6K0
linux进程调度
进程可以分为实时进程和普通进程,对于这两种不同类型的进程肯定有不同的调度策略,task_struct中的policy就用来表示调度策略。
你的益达
2020/08/12
8.1K0
linux进程调度
进程调度
实时优先级范围是0到MAX_RT_PRIO-1(即99),而普通进程的静态优先级范围是从MAX_RT_PRIO到MAX_PRIO-1(即100到139)。值越大静态优先级越低。
233333
2018/09/14
7870
Linux进程调度器的设计--Linux进程的管理与调度(十七)
调度器面对的情形就是这样, 其任务是在程序之间共享CPU时间, 创造并行执行的错觉, 该任务分为两个不同的部分, 其中一个涉及调度策略, 另外一个涉及上下文切换.
233333
2018/12/04
3.6K0
Linux进程调度器的设计--Linux进程的管理与调度(十七)
Linux进程调度器概述--Linux进程的管理与调度(十五)
调度器面对的情形就是这样, 其任务是在程序之间共享CPU时间, 创造并行执行的错觉, 该任务分为两个不同的部分, 其中一个涉及调度策略, 另外一个涉及上下文切换.
233333
2018/10/09
3.6K0
Linux进程调度器概述--Linux进程的管理与调度(十五)
进程优先级详解
Linux 中采用了两种不同的优先级范围,一种是 nice 值,一种是实时优先级。在上一篇粗略的说了一下 nice 值和实时优先级,仍有不少疑问,本文来详细说明一下进程优先级。linux 内核版本为 linux 2.6.34 。
233333
2023/12/03
3280
进程调度策略
根据优先级,进程分为实时进程和非实时进程(普通进程),Linux的进程优先级范围为[0, 139],其中实时进程优先级的范围为[0, 99],非实时进程的优先级为[100, 139),优先级的数值越低,说明优先级越高。
opencode
2022/12/26
7810
【Linux 内核】调度器 ⑧ ( 进程优先级源码 include\linux\sched\prio.h | 进程分类 | 实时进程 | 普通进程 | 进程优先级数值 | 0 ~ 99 实时进程 )
中 , 简单介绍了 进程优先级概念 , 本篇博客中开始介绍 Linux 内核中优先级相关源码 ;
韩曙亮
2023/03/30
3.6K0
Linux Kernel调度器的过去,现在和未来
Linux Kernel Development 一书中,关于 Linux 的进程调度器并没有讲解的很全面,只是提到了 CFS 调度器的基本思想和一些实现细节;并没有 Linux 早期的调度器介绍,以及最近这些年新增的在内核源码树外维护的调度器思想。所以在经过一番搜寻后,看到了这篇论文 A complete guide to Linux process scheduling,对 Linux 的调度器历史进行了回顾,并且相对细致地讲解了 CFS 调度器。整体来说,虽然比较啰嗦,但是对于想要知道更多细节的我来说非常适合,所以就有了翻译它的冲动。当然,在学习过程也参考了其它论文。下面开启学习之旅吧,如有任何问题,欢迎指正~
刘盼
2020/04/20
2.7K0
Linux Kernel调度器的过去,现在和未来
调度器及CFS调度器
调度:就是按照某种调度的算法设计,从进程的就绪队列中选择进程分配CPU,主要是协调进程对CPU等相关资源的使用。
laputa
2022/11/21
1.1K0
【Linux 内核】进程优先级与调度策略 ① ( SCHED_FIFO 调度策略 | SCHED_RR 调度策略 | 进程优先级 )
参考 【Linux 内核】调度器 ⑨ ( Linux 内核调度策略 | SCHED_NORMAL 策略 | SCHED_FIFO 策略 | SCHED_NORMAL 策略 | SCHED_BATCH策略 ) 博客 , 介绍了 Linux 内核相关的调度策略 ;
韩曙亮
2023/03/30
6.5K0
Linux 进程管理之调度和进程切换
每个CPU都有一个运行队列,每个运行队列中有三个调度队列,task作为调度实体加入到各自的调度队列中。
刘盼
2021/04/29
2K0
Linux 进程管理之调度和进程切换
Linux CFS调度器之负荷权重load_weight--Linux进程的管理与调度(二十五)
负荷权重用struct load_weight数据结构来表示, 保存着进程权重值weight。其定义在/include/linux/sched.h, v=4.6, L1195, 如下所示
233333
2018/12/11
1.6K0
Linux CFS调度器之负荷权重load_weight--Linux进程的管理与调度(二十五)
linux进程调度
  进程提供了两种优先级,一种是普通的进程优先级,第二个是实时优先级。前者适用SCHED_NORMAL调度策略,后者可选SCHED_FIFO或SCHED_RR调度策略。任何时候,实时进程的优先级都高于普通进程,实时进程只会被更高级的实时进程抢占,同级实时进程之间是按照FIFO(一次机会做完)或者RR(多次轮转)规则调度的。 1.实时进程的调度  实时进程,只有静态优先级,因为内核不会再根据休眠等因素对其静态优先级做调整,其范围在0~MAX_RT_PRIO-1间。默认MAX_RT_PRIO配置为100,也即,
Mister24
2018/05/14
3.3K0
CFS 调度器数据结构篇
在上一节我们了解了CFS的设计原理,包括CFS的引入,CFS是如何实现公平,CFS工作原理的。本小节我们重点在分析CFS调度器中涉及到的一些常见的数据结构,对这些数据结构做一个简单的概括,梳理各个数据结构之间的关系图出来。
DragonKingZhu
2020/03/24
1.3K0
CFS 调度器数据结构篇
linux 系统调度器(四) -- 利用 chrt 命令查询与修改进程调度器
在上一篇文章中,我们知道,到 Linux 2.6.23 版本后,linux 实际上维护了一组调度器来实现不同的调度需要,它们被分为了四层:
用户3147702
2022/09/23
5.5K0
linux 系统调度器(四) -- 利用 chrt 命令查询与修改进程调度器
Linux进程调度策略的发展和演变--Linux进程的管理与调度(十六)
调度器面对的情形就是这样, 其任务是在程序之间共享CPU时间, 创造并行执行的错觉, 该任务分为两个不同的部分, 其中一个涉及调度策略, 另外一个涉及上下文切换.
233333
2018/11/20
2.3K0
【Linux 内核】调度器 ⑨ ( Linux 内核调度策略 | SCHED_NORMAL 策略 | SCHED_FIFO 策略 | SCHED_NORMAL 策略 | SCHED_BATCH策略 )
" Linux 应用进程 " 可以根据 " Linux 内核 " 提供的 " 调度策略 " 选择 " 调度器 " ;
韩曙亮
2023/03/30
1.6K0
【Linux 内核】调度器 ⑨ ( Linux 内核调度策略 | SCHED_NORMAL 策略 | SCHED_FIFO 策略 | SCHED_NORMAL 策略 | SCHED_BATCH策略 )
【Linux 内核】进程管理 - 进程优先级 ② ( prio 调度优先级 | static_prio 静态优先级 | normal_prio 正常优先级 | rt_priority 实时优先级 )
在 linux-5.6.18\include\linux\sched.h 头文件中 task_struct " 进程描述符 " 结构体 中定义了 进程优先级字段如下 :
韩曙亮
2023/03/30
4.9K0
【Linux 内核】CFS 调度器 ① ( CFS 完全公平调度器概念 | CFS 调度器虚拟时钟 Virtual Runtime 概念 | 四种进程优先级 | 五种调度类 )
CFS 调度器 ( Completely Fair Scheduler ) 是 " 完全公平调度器 " , " 完全公平调度算法 " 对每个 进程 都是 公平 的 ,
韩曙亮
2023/03/30
2.1K0
【Linux 内核】CFS 调度器 ① ( CFS 完全公平调度器概念 | CFS 调度器虚拟时钟 Virtual Runtime 概念 | 四种进程优先级 | 五种调度类 )
推荐阅读
Linux进程优先级的处理--Linux进程的管理与调度(二十二)
3.6K0
linux进程调度
8.1K0
进程调度
7870
Linux进程调度器的设计--Linux进程的管理与调度(十七)
3.6K0
Linux进程调度器概述--Linux进程的管理与调度(十五)
3.6K0
进程优先级详解
3280
进程调度策略
7810
【Linux 内核】调度器 ⑧ ( 进程优先级源码 include\linux\sched\prio.h | 进程分类 | 实时进程 | 普通进程 | 进程优先级数值 | 0 ~ 99 实时进程 )
3.6K0
Linux Kernel调度器的过去,现在和未来
2.7K0
调度器及CFS调度器
1.1K0
【Linux 内核】进程优先级与调度策略 ① ( SCHED_FIFO 调度策略 | SCHED_RR 调度策略 | 进程优先级 )
6.5K0
Linux 进程管理之调度和进程切换
2K0
Linux CFS调度器之负荷权重load_weight--Linux进程的管理与调度(二十五)
1.6K0
linux进程调度
3.3K0
CFS 调度器数据结构篇
1.3K0
linux 系统调度器(四) -- 利用 chrt 命令查询与修改进程调度器
5.5K0
Linux进程调度策略的发展和演变--Linux进程的管理与调度(十六)
2.3K0
【Linux 内核】调度器 ⑨ ( Linux 内核调度策略 | SCHED_NORMAL 策略 | SCHED_FIFO 策略 | SCHED_NORMAL 策略 | SCHED_BATCH策略 )
1.6K0
【Linux 内核】进程管理 - 进程优先级 ② ( prio 调度优先级 | static_prio 静态优先级 | normal_prio 正常优先级 | rt_priority 实时优先级 )
4.9K0
【Linux 内核】CFS 调度器 ① ( CFS 完全公平调度器概念 | CFS 调度器虚拟时钟 Virtual Runtime 概念 | 四种进程优先级 | 五种调度类 )
2.1K0
相关推荐
Linux进程优先级的处理--Linux进程的管理与调度(二十二)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验