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,否则返回0prio = MAX_RT_PRIO-1 - p->rt_priority;        // 进程为实时进程,prio 值为实时优先级值做相关运算得到: prio = MAX_RT_PRIO -1 - p->rt_priorityelseprio = __normal_prio(p);                // 进程为非实时进程,则 prio 值为静态优先级值,即 prio = p->static_prioreturn 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_prioreturn 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,否则返回0prio = MAX_RT_PRIO-1 - p->rt_priority;        // 进程为实时进程,prio 值为实时优先级值做相关运算得到: prio = MAX_RT_PRIO -1 - p->rt_priorityelseprio = __normal_prio(p);                // 进程为非实时进程,则 prio 值为静态优先级值,即 prio = p->static_prioreturn 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 值进行设置。

转载于:https://www.cnblogs.com/tongye/p/9615625.html

Linux内核学习笔记(6)-- 进程优先级详解(prio、static_prio、normal_prio、rt_priority)...相关推荐

  1. 操作系统进程学习(Linux 内核学习笔记)

    操作系统进程学习(Linux 内核学习笔记) 进程优先级 并非所有进程都具有相同的重要性.除了大多数我们所熟悉的进程优先级之外,进程还有不同的关键度类别,以满足不同需求.首先进程比较粗糙的划分,进程可 ...

  2. ELK学习笔记之Logstash详解

    0x00 Logstash概述 官方介绍:Logstash is an open source data collection engine with real-time pipelining cap ...

  3. expect学习笔记及实例详解【转】

    1. expect是基于tcl演变而来的,所以很多语法和tcl类似,基本的语法如下所示: 1.1 首行加上/usr/bin/expect 1.2 spawn: 后面加上需要执行的shell命令,比如说 ...

  4. Java中大数据数组,Java基础学习笔记之数组详解

    摘要:这篇Java开发技术栏目下的"Java基础学习笔记之数组详解",介绍的技术点是"java基础学习笔记.基础学习笔记.Java基础.数组详解.学习笔记.Java&qu ...

  5. Linux 内核中RAID5源码详解之守护进程raid5d

    Linux 内核中RAID5源码详解之守护进程raid5d 对于一个人,大脑支配着他的一举一动:对于一支部队,指挥中心控制着它的所有活动:同样,对于内核中的RAID5,也需要一个像大脑一样的东西来支配 ...

  6. oracle scn 重置,学习笔记:Oracle SCN详解 SCN与Oracle数据库恢复的关系

    天萃荷净 分享一篇关于Oracle SCN的详解,介绍SCN与Oracle数据库恢复的关系和SCN在数据库中的作用 一.为什么需要System checkpoint SCN号与Datafile Che ...

  7. 我的Linux内核学习笔记

    在开始今天的内容之前,其实有一些题外话可以和大家分享一下.自从工作以来,我个人一直都有一个观点.那就是怎么样利用简单的代码来说明开发中的问题,或者是解释软件中的原理,这是一个很高的学问.有些道理看上去 ...

  8. 深度:一文看懂Linux内核,Linux内核架构和工作原理详解

    简介 作用是将应用层序的请求传递给硬件,并充当底层驱动程序,对系统中的各种设备和组件进行寻址.目前支持模块的动态装卸(裁剪).Linux内核就是基于这个策略实现的.Linux进程1.采用层次结构,每个 ...

  9. Linux内核架构和工作原理详解

    作用是将应用层序的请求传递给硬件,并充当底层驱动程序,对系统中的各种设备和组件进行寻址.目前支持模块的动态装卸(裁剪).Linux内核就是基于这个策略实现的.Linux进程1.采用层次结构,每个进程都 ...

最新文章

  1. 今日 Paper | 高效骨干搜索;学习扩充;最小人脸检测器;​DEPARA等
  2. Stimulsoft Reports.Silverlight 2013.2下载
  3. opensuse13.2安装 sass和compass
  4. inputstream转fileinputstream对象_FileInputStream类:文件字节输入流
  5. java dispatchevent_java事件处理机制
  6. python中 [ 闭包 ] 小结
  7. VMware ESXi客户端连接控制台时提示VMRC控制台连接已断开...正在尝试重新连接的解决方法...
  8. 企业局域网管理软件_WorkWin局域网管理软件 企业必备监控神器
  9. 史上最简单的制作安装系统U盘工具
  10. JAVA面试问题及答案
  11. 一键上传文档至Google文档
  12. OpenWrt一些小问题的解决方法
  13. 基于ITIL的医院信息化服务管理实践(客户说)
  14. redis分布式代理工具选型与功能验证
  15. Python中的File(文件)操作
  16. cocos2d-js 游戏源码
  17. 戴尔710服务器硬盘灯,DELL R710服务器,做RAID5,更换一个硬盘后硬盘灯,黄灯和绿灯交替不断亮??急急求助...
  18. 织梦插件-站长必备免费织梦插件快速收录
  19. 在PyTorch中使用Seq2Seq构建的神经机器翻译模型
  20. ZX内存遍历工具1.0

热门文章

  1. html怎么让两个表单并行,HMLT/CSS:如何将一个表单分成两个部分,使其并排显示?
  2. 2022年Java面经分享,腾讯Java面试题
  3. fifa14计算机都是,EA高管表示《FIFA》玩家的电脑配置普遍较低
  4. ubuntu下nginx配置
  5. 【愚公系列】2022年02月 wireshark系列-数据抓包分析之UDP协议
  6. 新编组织行为学作业 (3)
  7. matlab的linprog函数
  8. CSS定义如何计算一个元素的总宽度和总高度
  9. 计算输入日期的前一天
  10. Redis知识点总结(操作入门级)