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

图解Linux进程调度(二)

作者头像
用户6280468
发布2022-06-09 21:24:35
1.6K0
发布2022-06-09 21:24:35
举报
文章被收录于专栏:txp玩Linux

优先级与调度策略:

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

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

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

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

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

代码语言:javascript
复制
unsigned int policy;

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

代码语言:javascript
复制
#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
复制
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
复制

/* 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
复制
p->prio = effective_prio(p);

看一下 effective_prio 的定义:

代码语言:javascript
复制
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
复制
#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
复制
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 删除。

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 优先级与调度策略:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档