首页 > 系统相关 >进程优先级详解

进程优先级详解

时间:2023-12-02 23:01:10浏览次数:29  
标签:RT 优先级 prio PRIO MAX priority 详解 进程

Linux 中采用了两种不同的优先级范围,一种是 nice 值,一种是实时优先级。在上一篇粗略的说了一下 nice 值和实时优先级,仍有不少疑问,本文来详细说明一下进程优先级。linux 内核版本为 linux 2.6.34 。

进程优先级的相关信息,存放在进程描述符 task_struct 中:

struct task_struct {
        ...
    int prio, static_prio, normal_prio;
    unsigned int rt_priority;
        ...
}

可以看到,有四种进程优先级: prio、static_prio、normal_prio 和 rt_priority,它们的具体定义在 kernel/sched.c 中,在介绍这四种优先级之前,先介绍一下以下宏定义:

/* linux-kernel 2.6.34 /include/linux/sched.h */
 
/*
 * Priority of a process goes from 0..MAX_PRIO-1, valid RT
 * priority is 0..MAX_RT_PRIO-1, and SCHED_NORMAL/SCHED_BATCH
 * tasks are in the range MAX_RT_PRIO..MAX_PRIO-1. Priority
 * values are inverted: lower p->prio value means higher priority.
 *
 * The MAX_USER_RT_PRIO value allows the actual maximum
 * RT priority to be separate from the value exported to
 * user-space.  This allows kernel threads to set their
 * priority to a value higher than any user task. Note:
 * MAX_RT_PRIO must not be smaller than MAX_USER_RT_PRIO.
 */
#define MAX_USER_RT_PRIO     100
#define MAX_RT_PRIO          MAX_USER_RT_PRIO
 
#define MAX_PRIO            (MAX_RT_PRIO + 40)
#define DEFAULT_PRIO        (MAX_RT_PRIO + 20)    // 默认优先级,对应 nice 值为 0 的静态优先级

1、prio 动态优先级

prio 的值是调度器最终使用的优先级数值,即调度器选择一个进程时实际选择的值。prio 值越小,表明进程的优先级越高 。prio 值的取值范围是 0 ~ MAX_PRIO,即 0 ~ 139(包括 0 和 139),根据调度策略的不同,又可以分为两个区间,其中区间 0 ~ 99 的属于实时进程,区间 100 ~139 的为非实时进程。用语言不好描述,我们通过内核代码来详细描述 prio:

/* linux-kernel 2.6.34  /kernel/sched.c  */
 
#include "sched_idletask.c"
#include "sched_fair.c"
#include "sched_rt.c"
#ifdef CONFIG_SCHED_DEBUG
#include "sched_debug.c"
#endif
 
/*
 * __normal_prio - return the priority that is based on the static prio
 */
static inline int __normal_prio(struct task_struct *p)    // _normal_prio 函数,返回静态优先级值
{
    return p->static_prio;
}
 
/*
 * Calculate the expected normal priority: i.e. priority
 * without taking RT-inheritance into account. Might be
 * boosted by interactivity modifiers. Changes upon fork,
 * setprio syscalls, and whenever the interactivity
 * estimator recalculates.
 */
static inline int normal_prio(struct task_struct *p)    // normal_prio 函数
{
    int prio;
 
    if (task_has_rt_policy(p))                 // task_has_rt_policy 函数,判断进程是否为实时进程,若为实时进程,则返回1,否则返回0
        prio = MAX_RT_PRIO-1 - p->rt_priority;        // 进程为实时进程,prio 值为实时优先级值做相关运算得到: prio = MAX_RT_PRIO -1 - p->rt_priority
    else
        prio = __normal_prio(p);                // 进程为非实时进程,则 prio 值为静态优先级值,即 prio = p->static_prio
    return prio;
}
 
/*
 * Calculate the current priority, i.e. the priority
 * taken into account by the scheduler. This value might
 * be boosted by RT tasks, or might be boosted by
 * interactivity modifiers. Will be RT if the task got
 * RT-boosted. If not then it returns p->normal_prio.
 */
static int effective_prio(struct task_struct *p)       // effective_prio 函数,计算进程的有效优先级,即prio值,这个值是最终调度器所使用的优先级值
{
    p->normal_prio = normal_prio(p);              // 计算 normal_prio 的值
    /*
     * If we are RT tasks or we were boosted to RT priority,
     * keep the priority unchanged. Otherwise, update priority
     * to the normal priority:
     */
    if (!rt_prio(p->prio))
        return p->normal_prio;                  // 若进程是非实时进程,则返回 normal_prio 值,这时的 normal_prio = static_prio
    return p->prio;                         // 否则,返回值不变,依然为 prio 值,此时 prio = MAX_RT_PRIO -1 - p->rt_priority
} 
 
/*********************** 函数 set_user_nice ****************************************/
void set_user_nice(struct task_struct *p, long nice)
{
     ....
    p->prio = effective_prio(p);                   // 在函数 set_user_nice 中,调用 effective_prio 函数来设置进程的 prio 值
     ....
}

从上面代码中我们知道,当进程为实时进程时, prio 的值由实时优先级值(rt_priority)计算得来;当进程为非实时进程时,prio 的值由静态优先级值(static_prio)得来。即:

prio = MAX_RT_PRIO - 1 - rt_priority // 进程为实时进程

prio = static_prio          // 进程为非实时进程

简单计算上面的两个式子,可以知道,prio 值的范围是 0 ~ 139 。

2、static_prio 静态优先级

静态优先级不会随时间改变,内核不会主动修改它,只能通过系统调用 nice 去修改 static_prio,如下:

/*
 * Convert user-nice values [ -20 ... 0 ... 19 ]
 * to static priority [ MAX_RT_PRIO..MAX_PRIO-1 ],
 * and back.
 */
#define NICE_TO_PRIO(nice)    (MAX_RT_PRIO + (nice) + 20)
#define PRIO_TO_NICE(prio)    ((prio) - MAX_RT_PRIO - 20)
#define TASK_NICE(p)        PRIO_TO_NICE((p)->static_prio)
 
/*
 * 'User priority' is the nice value converted to something we
 * can work with better when scaling various scheduler parameters,
 * it's a [ 0 ... 39 ] range.
 */
#define USER_PRIO(p)        ((p)-MAX_RT_PRIO)
#define TASK_USER_PRIO(p)    USER_PRIO((p)->static_prio)
#define MAX_USER_PRIO        (USER_PRIO(MAX_PRIO))
 
/********************* 函数 set_user_nice *****************************/
p->static_prio = NICE_TO_PRIO(nice);        // 当有需要时,系统会通过调用 NICE_TO_PRIO() 来修改 static_prio 的值

由上面代码知道,我们可以通过调用 NICE_TO_PRIO(nice) 来修改 static_prio 的值, static_prio 值的计算方法如下:

static_prio = MAX_RT_PRIO + nice +20

MAX_RT_PRIO 的值为100,nice 的范围是 -20 ~ +19,故 static_prio 值的范围是 100 ~ 139。 static_prio 的值越小,表明进程的静态优先级越高 。

3、normal_prio 归一化优先级

normal_prio 的值取决于静态优先级和调度策略,可以通过 _setscheduler 函数来设置 normal_prio 的值 。对于非实时进程,normal_prio 的值就等于静态优先级值 static_prio;对于实时进程,normal_prio = MAX_RT_PRIO-1 - p->rt_priority。代码如下:

static inline int normal_prio(struct task_struct *p)    // normal_prio 函数
{
    int prio;
 
    if (task_has_rt_policy(p))                 // task_has_rt_policy 函数,判断进程是否为实时进程,若为实时进程,则返回1,否则返回0
        prio = MAX_RT_PRIO-1 - p->rt_priority;        // 进程为实时进程,prio 值为实时优先级值做相关运算得到: prio = MAX_RT_PRIO -1 - p->rt_priority
    else
        prio = __normal_prio(p);                // 进程为非实时进程,则 prio 值为静态优先级值,即 prio = p->static_prio
    return prio;
}

4、rt_priority 实时优先级

rt_priority 值的范围是 0 ~ 99,只对实时进程有效。由式子:

prio = MAX_RT_PRIO-1 - p->rt_priority; 

知道,rt_priority 值越大,则 prio 值越小,故 实时优先级(rt_priority)的值越大,意味着进程优先级越高。

rt_priority 的值也是取决于调度策略的,可以在 _setscheduler 函数中对 rt_priority 值进行设置。

标签:RT,优先级,prio,PRIO,MAX,priority,详解,进程
From: https://www.cnblogs.com/linhaostudy/p/17872412.html

相关文章

  • 详解十大经典排序算法(二):选择排序(Selection Sort)
    算法原理选择排序通过重复选择数组中最小元素,将其与未排序部分的第一个元素交换,实现排序。算法描述选择排序是一种简单的排序算法,它每次从待排序的元素中选择最小(或最大)的元素,将其放到已排序序列的末尾,直到整个序列排序完成。选择排序的基本思想是通过不断选择剩余元素中的最小(或......
  • SMTP操作使用详解并通过python进行smtp邮件发送示例
    转载请注明出处:1.SMTP     SMTP 的全称是“SimpleMailTransferProtocol”,即简单邮件传输协议。它是一组用于从源地址到目的地址传输邮件的规范,通过它来控制邮件的中转方式。SMTP协议属于TCP/IP协议簇,它帮助每台计算机在发送或中转信件时找到下一个目的地。SMTP服......
  • 学习C语言必备的基础知识详解
    (⽬录)前言学习C语言的第一步,肯定是要先去学习了解一下相关的概念和符号,我们写的代码就是由一堆规定好的有特殊含义的符号组成的。1、数据类型C语言的数据类型细分出来会有很多种,每种数据类型占内存大小都不同,对于刚接触编程语言的人来说,确实很让人头疼。其实存在这么多的类型,......
  • 内存取证volatility工具命令详解
    一、环境安装1.kali下安装Volatility2注意:一般Volatility2比Volatility3好用wgethttps://bootstrap.pypa.io/pip/2.7/get-pip.pypython2get-pip.pypython2-mpipinstallCryptopython2-mpipinstallpycryptodomepython2-mpipinstallpytzpython2-......
  • 微服务调用方式详解
    在微服务架构中,需要调用很多服务才能完成一项功能。服务之间如何互相调用就变成微服务架构中的一个关键问题。服务调用有两种方式,一种是RPC(RemoteProcedureCall)方式,另一种是事件驱动(Event-driven)方式,也就是发消息方式。消息方式是松耦合方式,比紧耦合的RPC方式要优越,但RPC方式如......
  • Java流Stream使用详解(中)
    一、Stream流的中间方法名称说明Stream<T> filter(Predicate<?superT> predicate)过滤Stream<T> limit(longmaxSize)获取前几个元素Stream<T> skip(longn)跳过前几个元素Stream<T> distinct()元素去重,依赖(hashCode和equals方法)static<T> Stream<T> concat(Stream......
  • Java之API详解之Biginteger类的详解
     6BigInteger类6.1引入平时在存储整数的时候,Java中默认是int类型,int类型有取值范围:-2147483648~2147483647。如果数字过大,我们可以使用long类型,但是如果long类型也表示不下怎么办呢?就需要用到BigInteger,可以理解为:大的整数。有多大呢?理论上最大到42亿的21亿次方基本上在内存撑......
  • 查看进程线程的方法
    windows任务管理器可以查看进程和线程数,也可以用来杀死进程tasklist查看进程taskkill杀死进程netstat-ano|findstr端口号查看某个端口号下的进程taskkill/f/pid强制杀死某个进程linuxps-ef查看所有进程ps-fT-p<PID>查看某个进程(PID)的所有线程kill杀死进程......
  • Java集合框架详解
    Java集合框架是什么?Java中的集合框架指的是一组接口、类和算法,用于存储和操作一组对象。这些对象可以是基本类型、自定义类型或其他Java对象集合框架提供了更加高效、灵活和功能丰富的数据结构,而不限于数组或其他简单的数据结构。通过使用Java的集合框架,可以大大提高代码的可......
  • Java设计模式-策略模式详解
    1.策略模式基本了解策略模式(StrategyPattern)是一种行为型设计模式,它定义了一组可以相互替换的算法,使得客户端可以根据不同的需求选择不同的算法,将对象和行为分开。在策略模式中,我们创建了一个策略接口,该接口定义了所有必需的方法。然后,我们创建了实现了该策略接口的具体策略......