首页 > 系统相关 >Linux调度中的任务优先级机制

Linux调度中的任务优先级机制

时间:2023-10-12 19:00:12浏览次数:69  
标签:rt task 优先级 prio normal 调度 static Linux

前言

在阅读源码的过程中发现一个task_struct包含四个优先级相关的成员,priostatic_prionormal_priort_priority这几个优先级值有什么区别和联系呢?

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

内核中的优先级范围

+----+-------------------------+---------------+
| -1 |0                      99|100         139|   
+----+-------------------------+---------------+

内核中管理多任务的调度类有三个,分别是dl_sched_classrt_sched_classfair_sched_class。其中-1优先级用于所有的dl-task[0,99]rt-task的优先级,[100,139]normal-task的优先级。在内核中值越低其优先级越高。

static_prio

在内核中,static_prio用于normal-task,这个值与nice存在如下转化关系:static_prio = nice + 120。可以看到static_prionice值是绑定的。
内核中设置一个进程的优先级的入口是系统调用sys_setpriority,这个系统调用可以设置用户、进程组、进程的优先级。当设置某个进程的nice值时会进入到set_user_nice

void set_user_nice(struct task_struct *p, long nice)
{
    /* rt or deadline task */
    if (task_has_dl_policy(p) || task_has_rt_policy(p)) {
        p->static_prio = NICE_TO_PRIO(nice);
        goto out_unlock;
    }
    /* cfs task */
    p->static_prio = NICE_TO_PRIO(nice);
    set_load_weight(p, true);
    p->prio = effective_prio(p);
}

如果设置一个deadline任务或者rt-taskstatic_prio时,该操作是允许的,但是并不会产生实质影响,因为rt_sched_classdl_sched_class并不看这个值。对于normal-task来说set_user_nice除了更新static_prio以外,set_load_weight还会更新normal-task以及cfs_rq的权重信息。

CFS中有一类特别的任务,这些任务的调度策略为SCHED_IDLE,这些任务的权重值与优先级无关,因此对于使用该策略的task修改其nice值没有意义。

static void set_load_weight(struct task_struct *p, bool update_load)
{
    int prio = p->static_prio - MAX_RT_PRIO;
    struct load_weight *load = &p->se.load;
    /* idle policy */
    if (idle_policy(p->policy)) {
        load->weight = scale_load(WEIGHT_IDLEPRIO);
        load->inv_weight = WMULT_IDLEPRIO;
        return;
    }
    /* normal cfs task */
    reweight_task(p, prio);
}

以上只是static_prio产生变化的一种场景,一个任务的生命周期内static_prio的变化的情况有两种:

  • 系统调用fork:在新任务初始化时,sched_fork会重置或者继承。
  • 系统调用sys_setpriority中,调用set_user_nice更新。

NOTE:系统调用sched_setscheduler支持修改任务的调度类的同时可以设置优先级,但是该参数是实时调度器使用的优先级,对于切换到CFS的场景,此时更新权重信息使用的是任务自身的static_prio。这样来看sys_setpriority是修改static_prio的唯一接口。

rt_priority

rt_priority是实时调度器使用的优先级,在设置一个rt-taskrt_priority时,输入值的有效范围为[0,99],与nice值不同的是rt_priority越大其rt-task的优先级就越大,但是内核为了让语义统一在使用时做了转化。real-prio = MAX_RT_PRIO - 1 - rt_priority = 99 - rt_priority,优先级越大其计算出的值越小。但是在外部使用时可以按照正常逻辑来设置优先级。

normal_prio

normal_prio的值与当前所属的调度策略有关,dl-tasknormal_prio固定-1rt-tasknormal_prio99 - rt_prioritynormal-tasknormal_priostatic_prionormal_prio实现了static_prio值和rt_priority优先级的统一,normal_prio值越小其优先级越高。

prio

prio是做调度决策时真正使用的优先级,在正常情况下与normal_prio一致。但是在一些特殊场景下需要在不修改static_priort_priority的情况下临时提高prio

典型的就是优先级反转问题,在以下两个场景需要临时提高prio

  • rt-task持有mutex A,另一个dl-task阻塞在mutex A上。
  • rt-task持有mutex A,另一个rt-task阻塞在mutex A上,并且该任务可以抢占当前运行中的进程。

在这里持锁的task称作p,阻塞的task称作pi。如果不做处理,某个中间优先级的task有可能会抢占p执行,导致因为锁阻塞的pi任务的实时性得不到保障。解决方法就是通过优先级继承让p持锁过程中priopiprio保持一致,让p能够尽快执行结束后释放mutex

总结

四类优先级的范围与用途一览:

类型 范围 用途 设置方法
static_prio [100,139] normal-task优先级 通过set_priority系统调用设置nice值转化为static_prio,将nice值从[-20,19]映射到[100,139]nice值越高优先级越低
rt_priority [0,99] rt-task优先级 通过sched_setscheduler系统调用设置, 输入范围为[0,99],值越高优先级越高
normal_prio [-1,139] 优先级的语义统一 normal_prio与调度类对应,fair_sched_class时与static_prio一致,rt_sched_class时将rt_priority[0,99]映射到[99,0]dl_sched_class时固定-1
prio [-1,139] 决策时真正使用的优先级 一般与normal_prio一致,特殊情况可以临时提高优先级

从优先级机制的设计上来看,真正的优先级prio会按顺序考虑优先级临时提高、调度类、调度类对应的优先级设置。临时提高的特殊情况下可以不考虑任务当前的调度类与优先级参数设置。普通情况下使用normal_prio,而normal_prio会根据当前的调度类和参数设置进行调整。

另外在API上,设置优先级的接口有两个:

  • set_priority可以改变static_prio的值,输入参数为nice
  • sched_setscheduler可以设置调度器以及rt_priority(如果调度类为rt_sched_class)。输入参数为rt_priority的值以及调度策略policy(可找到对应的调度器)。

相关的linux命令有:

  • renice可以调整normal-tasknice值。
  • chrt可以设置调度策略,如果是rt-task可以设置rt_priority
  • cat /proc/{pid}/sched 可以查看priopolicy

标签:rt,task,优先级,prio,normal,调度,static,Linux
From: https://www.cnblogs.com/wodemia/p/17760136.html

相关文章

  • Linux系统管理(1) 开启与禁用普通用户sudo权限
    1.sudo命令简介sudo是Linux系统管理指令,是允许系统管理员让普通用户执行一些或者全部root命令的一个工具。Linux系统下,为了安全,一般来说我们操作都是在普通用户下操作,但有时普通用户需要用到root权限,比如在安装软件的时候。这个时候如果我们切回root用户下效率就会比较低,所以用su......
  • 完全指南:在 Linux 中如何打印和管理打印机
    完全指南:在Linux中如何打印和管理打印机https://linux.cn/article-9538-1.html 作者:IanShields译者:LCTT qhwdw|2018-04-1213:43  评论:1    Linux中的打印虽然现在大量的沟通都是电子化和无纸化的,但是在我们的公司中还有大量的材料需要打印。银行结......
  • linux 查看java log
    Linux查看Java日志在开发和运维过程中,我们经常需要查看Java应用程序的日志来追踪问题和进行故障排除。本文将介绍如何在Linux环境中查看Java日志,并提供一些常用的命令和工具。1.查看日志文件Java应用程序通常会将日志输出到一个或多个文件中。我们首先需要找到日志文件的位置,然......
  • AWVS15.2 Crack Windows&& Linux
    Windows安装过程https://www.ddosi.org/awvs-15-2/Linux&&Kali安装过程https://fahai.org/jszt/18.htmlQ:好像本机访问不了,但是能ping通......
  • Linux C语言Shared Library共享库细节探究
    开发中遇到一个问题,比如有一个类库A,被类库B引用,类库B和类库A都被程序C引用。类库A中有一个全局变量G,要求同一个进程中使用的是同一个全局变量G。虽然看起来很简单,但是实际探究下来还有不少坑。如果不是类库如果AB都不是类库,而是直接引入源码编译,理论上比较方便解决。示例一p......
  • Linux之iostat
    Linux之iostat前言iostat主要用于监控系统设备的IO负载情况。iostat首次运行时显示自系统启动开始的各项统计信息,之后运行iostat将显示自上次运行该命令以后的统计信息。用户可以通过指定统计的次数和时间来获得所需的统计信息。1.命令功能:通过iostat方便查看CPU、网卡、tty......
  • Linux 日志按时间、按行截取方式
    Linux日志按时间、按行截取方式代码脚本之家 2023-10-0812:53 发表于上海收录于合集#linux2个#日志1个1.截取catalina.out某段时间内的日志信息:sed-n'/2023-09-23 14:00:/,/2023-09-23 15:00:/p'catalina.out>seg.log2.按行截取日志先按照关键字找到相应......
  • linux TCP 通信流程 套接字函数
    TCP和UDP  -> 传输层的协议UDP:用户数据报协议,面向无连接,可以单播,多播,广播,面向数据报(类似战争中无线电的广播),不可靠。TCP:传输控制协议,面向连接的,可靠的,基于字节流,仅支持单播传输(点对点)。UDP TCP......
  • Linux快捷键及History用法
    Linux快捷键及History用法1.bash的快捷键Ctrl+l清屏,相当于clear命令Ctrl+o执行当前命令,并重新显示本命令Ctrl+s阻止屏幕输出,锁定Ctrl+q允许屏幕输出,解锁Ctrl+c终止命令Ctrl+z挂起命令Ctrl+a光标移到命令行首,相当于HomeCtrl+e光标移到命令......
  • Linux 中awk命令根据索引文件批量提取列和行
     001、批量提取列,根据索引index.txt文件批量提取2、4、8、9列[root@pc1test2]#lsa.txtindex.txt[root@pc1test2]#cata.txt##测试文件00100200300400500600700800901001101201301401501601701801902002102202302402502602......