Linux内核学习笔记(6)-- 进程优先级详解(prio、static_prio、normal_prio、rt_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- - 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- - 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 值进行设置。
Linux内核学习笔记(6)-- 进程优先级详解(prio、static_prio、normal_prio、rt_priority)的更多相关文章
- linux命令学习笔记-eval命令详解
功能说明:重新运算求出参数的内容. 语 法:eval [参数] 补充说明:eval可读取一连串的参数,然后再依参数本身的特性来执行. 参 数:参数不限数目,彼此之间用分号分开. .eval命令将会首先 ...
- linux命令学习笔记:cut详解
cut命令从文件的每一行剪切字节.字符和字段并将它们写至标准输出.它是以文件的每一行作为处理对象的. 命令格式:cut [选项] [范围] 文件.选项用来指定单位(字节.字符还是字段),范围指定选项的 ...
- linux命令学习笔记-md5sum 命令详解
前言 在网络传输.设备之间转存.复制大文件等时,可能会出现传输前后数据不一致的情况.这种情况在网络这种相对更 不稳定的环境中,容易出现.那么校验文件的完整性,也是势在必行的. 使用说明 md5sum命 ...
- expect学习笔记及实例详解【转】
1. expect是基于tcl演变而来的,所以很多语法和tcl类似,基本的语法如下所示:1.1 首行加上/usr/bin/expect1.2 spawn: 后面加上需要执行的shell命令,比如说sp ...
- Linux内核学习笔记-2.进程管理
原创文章,转载请注明:Linux内核学习笔记-2.进程管理) By Lucio.Yang 部分内容来自:Linux Kernel Development(Third Edition),Robert L ...
- Linux内核学习笔记-1.简介和入门
原创文章,转载请注明:Linux内核学习笔记-1.简介和入门 By Lucio.Yang 部分内容来自:Linux Kernel Development(Third Edition),Robert L ...
- Linux内核学习笔记二——进程
Linux内核学习笔记二——进程 一 进程与线程 进程就是处于执行期的程序,包含了独立地址空间,多个执行线程等资源. 线程是进程中活动的对象,每个线程都拥有独立的程序计数器.进程栈和一组进程寄存器 ...
- 20135316王剑桥Linux内核学习笔记
王剑桥Linux内核学习笔记 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 计算机是如何工作的 个人理 ...
- (转)Linux内核参数设置sysctl命令详解
Linux内核参数设置sysctl命令详解 原文:https://www.zhukun.net/archives/8064 sysctl是一个允许您改变正在运行中的Linux系统的接口. 它包含一些 ...
随机推荐
- 当面试官问你sql优化的时候。。。
当面试官问你有关sql优化的问题时,直接拿笔写给他: 8-select 9-distinct<column_list> 1-from left_table 3-<join_type& ...
- Gradle Goodness: Automatic Clean Tasks
Gradle adds the task rule clean<Taskname> to our projects when we apply the base plugin. This ...
- java 进销存 crm 客户管理 库存管理 商户管理 springmvc SSM 项目
系统介绍: 1.系统采用主流的 SSM 框架 jsp JSTL bootstrap html5 (PC浏览器使用) 2.springmvc +spring4.3.7+ mybaits3.3 SSM ...
- 修改系统UITableViewCell的ImageView大小
代码如下: CGSize itemSize = CGSizeMake(, ); UIGraphicsBeginImageContext(itemSize); CGRect imageRect = CG ...
- 11-while循环基本使用
hm_02_第一个while循环.py def main(): i = 1 while i <= 3: print(i, 'Hello world') i += 1 print(i) 1 Hel ...
- Ubuntu16.04安装TFTP服务,完成开发板下载文件
1.安装TFTP服务 $ sudo apt-get install tftp-hpa tftpd-hpa 2.建立传递目录 $ mkdir tftp $ sudo chmod 777 tftp/ -R ...
- C语言——第一章,1.4程序开发过程
1.4程序开发过程 一,开发过程 1,分析问题,设计一种解决问题的途径(方案)★ 2,写出源代码 (*.c) 3,编译→(连接) *.obj→(*.exe) 4,运行*.exe (可执行程序) 二 ...
- vue中-webkit-box-orient:vertical打包放到线上不显示
解决方法: 1.找到build文件夹 下的webpack.prod.conf.js文件 2.注释new OptimizeCSSPlugin({ css ...
- lncRNA芯片重注释
.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table ...
- hadoop运维笔记
一. 故障处理部分 1.1. spark提交任务报错java.lang.NoClassDefFoundError: com/alibaba/fastjson/JSON 报错原因: 在运行环境没有找 ...