当前位置: 首页 > news >正文

linux任务优先级

这篇笔记记录了linux任务(指线程而非进程)优先级相关的概念,以及用户态可以用来操作这些优先级的系统调用。

基本概念

调度策略

linux内核中的调度器为任务定义了调度策略,也叫调度类,每个任务同一时刻都有唯一的调度策略,这些调度策略按照优先级从高到低依次为:

  • SCHED_DEADLINE

内核在3.14引入了Deadline调度策略,适用于那些需要周期性执行,并且必须在指定时间内完成的任务,其优先级最高。Deadline任务的使用场景较少,不是我们关注的重点。

  • SCHED_FIFO、SCHED_RR

采用这两种调度策略的任务叫做RT任务,这两种调度策略的优先级相同。

SCHED_FIFO任务一旦就绪,它会立即抢占比自己优先级低的任务,它一旦开始运行,除非被更高优先级的RT任务抢占,或者自己主动让出CPU,否则它会一直运行,这类任务没有时间片的限制。

SCHED_RR在SCHED_FIFO的基础上增加了时间片约束,它每次至多运行一段时间,之后如果还没有运行完也会让出CPU,继续下一次轮转,所以将Round-robin。

  • SCHED_OTHER、SCHED_BATCH、SCHED_IDLE

虽然这是三种调度策略,但是调度器基本上对它们不做区分,采用这三种调度策略的任务叫做普通任务。系统中大多数任务的调度策略都是这一类。这类任务共享CPU时间,由内核大名鼎鼎的CFS算法调度运行。

任务优先级

上面的调度策略决定了任务的第一级优先级,其概念是很清晰的,但是linux对于相同或同一类调度策略下各个任务之间的优先级概念就比较混乱,原因是用户态和内核态对这些优先级的叫法不统一。

用户态角度

对于普通任务,用户态是用nice值来表述它们的优先级的,nice值取值[-20, 19]。nice值越大,表示任务对CPU约nice,其优先级最低。

对于RT任务,用户态称其优先级为调度优先级,其值越大,优先级越高,取值范围为[sched_get_priority_min(2), sched_get_priority_min(2)],在linux上总是返回[1, 99]。

内核态角度

task_struct中定义了如下和优先级有关的字段,下面会介绍这些字段的含义。

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

对于普通任务,其用户态的nice值到了内核被转换为静态优先级保存到task_struct的static_prio字段中。下面的NICE_TO_PRIO宏会将用户态的nice值范围从[-20, 19]线性映射到[100, 139]范围,依然是值越小优先级越高。

#define MAX_USER_RT_PRIO    100
#define MAX_RT_PRIO        MAX_USER_RT_PRIO// NICE_WIDTH为40,表示nice的等级
#define MAX_PRIO        (MAX_RT_PRIO + NICE_WIDTH) // 139
#define DEFAULT_PRIO        (MAX_RT_PRIO + NICE_WIDTH / 2) // 120/** Convert user-nice values [ -20 ... 0 ... 19 ]* to static priority [ MAX_RT_PRIO..MAX_PRIO-1 ],* and back.*/
#define NICE_TO_PRIO(nice)    ((nice) + DEFAULT_PRIO)
#define PRIO_TO_NICE(prio)    ((prio) - DEFAULT_PRIO)void set_user_nice(struct task_struct *p, long nice)
{
...p->static_prio = NICE_TO_PRIO(nice);
}

对于RT任务,其用户态的调度优先级到了内核会被原封不动的保存到task_struct的rt_priority字段中,我们可以称之为实时优先级

static void __setscheduler_params(struct task_struct *p,const struct sched_attr *attr)
{
...p->rt_priority = attr->sched_priority;
}

内核态归一化优先级

任务的调度策略和优先级上述几种类型,内核态调度器在处理时将这些不同类型的调度策略和优先级进行了归一化处理,将它们映射到了一个线性区间,并使得它们单调性保持一致。归一化后的任务优先级保存在task_struct的normal_prio字段中。

static inline int __normal_prio(struct task_struct *p)
{return p->static_prio;
}static inline int normal_prio(struct task_struct *p)
{int prio;if (task_has_dl_policy(p))prio = MAX_DL_PRIO-1;else if (task_has_rt_policy(p))prio = MAX_RT_PRIO-1 - p->rt_priority; // MAX_RT_PRIO值为100,将RT任务的调度优先级单调性进行反转elseprio = __normal_prio(p);return prio;
}

归一化处理过程实现的效果如下图所示:

Deadline任务的normal_prio字段为-1,RT任务的normal_prio字段范围为[0, 100), 普通任务的normal_prio字段的范围为[100, 139),这样归一化优先级可以统一表达所有任务的优先级,并且规定归一化优先级值越小优先级越高。

内核态动态优先级

归一化优先级也不是调度器最终用于调度的优先级,这是因为调度器有时候会针对RT任务临时性的调整其优先级,因此又引入了动态优先级。动态优先级被保存在了task_struct的prio字段中。动态优先级通过effective_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)
{p->normal_prio = normal_prio(p);/** 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;return p->prio;
}

用户态接口

从系统手册sched(7)中可以看到,linux共提供了如下接口供用户态获取和调整任务的优先级。从下面的介绍中可以看到,不同的接口有其适用范围。

接口

描述

nice(2)

调整调用线程的nice值

getpriority(2)、setpriority(2)

操作进程、进程组或用户的所有进程的nice值

sched_setscheduler(2)、sched_getscheduler(2)

获取线程的调度策略,设置RT任务的调度策略和调度优先级

sched_setparam(2)、 sched_getparam(2)

sched_setscheduler(2)、sched_getscheduler(2)的变体

sched_setattr(2)、sched_getattr(2)

同时支持RT任务和普通任务调度策略和优先级的接口,该接口在实现上述接口的所有功能外还有额外的扩展功能

nice(2)

将调用线程的nice值加上参数inc,所以正的inc可以降低调用线程的优先级,负的inc可以提高调用线程的优先级。

int nice(int inc);

线程的nice值不是可以随意调整的,其可设置的上限受getrlimit(2)中的RLIMIT_NICE值限制。RLIMIT_NICE的取值范围为[1, 40],假设RLIMIT_NICE的配置为rlimit_cur,那么可设置的nice值上限为20 - rlimit_cur。

getpriority(2)、setpriority(2)

这两个接口用于获取和设置任务的nice值。which和who指定了要操作的任务范围,具体有:

  • which=PRIO_PROCESS,who=PID。任务范围为进程中所有线程;
  • which=PRIO_PGRP,who=进程组长PID。任务范围为进程组中所有线程;
  • which=PRIO_USER,who=UID。任务范围为该用户的所有线程;

可以看到,这两个接口的功能比nice(2)要更加的强大和灵活。

int getpriority(int which, id_t who);
int setpriority(int which, id_t who, int prio);

同样的,nice值的可设置上限受getrlimit(2)中的RLIMIT_NICE值限制。

sched_setscheduler(2)、sched_getscheduler(2)

当用sched_setscheduler(2)将线程的调度策略修改为普通任务时,其param->sched_priority必须为0,即该接口不能设置普通任务的nice值。当用它将线程的调度策略修改为RT任务时,可以用param->sched_priority为RT任务指定调度优先级。

sched_getscheduler(2)可以用来获取线程的调度策略。

int sched_setscheduler(pid_t pid, int policy, const struct sched_param *param);
int sched_getscheduler(pid_t pid);struct sched_param {...int sched_priority;...
};

这两个接口的pid为0时,表示操作的时调用线程。

sched_setparam(2)、 sched_getparam(2)

这组接口就是sched_setscheduler(2)、sched_getscheduler(2)的变体。

int sched_setparam(pid_t pid, const struct sched_param *param);
int sched_getparam(pid_t pid, struct sched_param *param);

sched_setattr(2)、sched_getattr(2)

这两个接口是linux特有的,并非POSIX接口,它们支持所有类型任务的调度策略和优先级调整。

int sched_setattr(pid_t pid, struct sched_attr *attr, unsigned int flags);
int sched_getattr(pid_t pid, struct sched_attr *attr, unsigned int size, unsigned int flags);struct sched_attr {u32 size;              /* Size of this structure */u32 sched_policy;      /* Policy (SCHED_*) */u64 sched_flags;       /* Flags */s32 sched_nice;        /* Nice value (SCHED_OTHER, SCHED_BATCH) */u32 sched_priority;    /* Static priority (SCHED_FIFO, SCHED_RR) *//* Remaining fields are for SCHED_DEADLINE */u64 sched_runtime;u64 sched_deadline;u64 sched_period;
};

相关文章:

linux任务优先级

这篇笔记记录了linux任务(指线程而非进程)优先级相关的概念,以及用户态可以用来操作这些优先级的系统调用。 基本概念 调度策略 linux内核中的调度器为任务定义了调度策略,也叫调度类,每个任务同一时刻都有唯一的调…...

JVM内存模型概述

这里主要分为五大块,分别是:本地方法栈、方法区、java堆、程序计数器和java栈。其中重点是方法区、java堆和java栈。 下面就把各个区域的性质总结一下:(说明,下面的只是结论,没有详细的对各个内存块进行详细…...

【JavaEE】CAS -- 多线程篇(7)

CAS 1. 什么是 CAS2. CAS 伪代码3. CAS 是怎么实现的4. CAS的应用4.1 实现原子类4.2 实现自旋锁 5. CAS 的 ABA 问题 1. 什么是 CAS CAS: 全称Compare and swap,字面意思:”比较并交换“能够比较和交换 某个寄存器中的值和内存中的值, 看是否相等, 如果相等, 则把另…...

18-spring 事务

文章目录 1. xml和注解配置方式的对象2.spring事务传播特性3. 注解事务的初始化流程4. 创建事务信息流程图5. 事务回滚流程图 1. xml和注解配置方式的对象 2.spring事务传播特性 事务传播行为类型说明PROPAGATION_REQUIRED如果当前没有事务,就新建一个事务&#xf…...

Qt窗体设计的布局

本文介绍Qt窗体的布局。 Qt窗体的布局分为手动布局和自动布局,手动布局即靠手工排布各控件的位置。而自动布局则是根据选择的布局类型自动按此类型排布各控件的位置,使用起来比较方便,本文主要介绍Qt的自动布局。 1.垂直布局 垂直布局就是…...

分布式锁 - 理论篇

一、为什么需要分布式锁 二、分布式锁实现 1.分布式锁演进 - 基本原理 我们可以同时去一个地方“占坑”,如果占到,就执行逻辑。否则就必须等待,直到释放锁。“占坑”可以去redis,可以去数据库,可以去任何大家都能访…...

复杂的菱形继承及菱形虚拟继承(详解)

复杂的菱形继承及菱形虚拟继承 复杂的菱形继承及菱形虚拟继承虚拟继承解决数据冗余和二义性的原理笔试面试题 复杂的菱形继承及菱形虚拟继承 单继承:一个子类只有一个直接父类时称这个继承关系为单继承 多继承:一个子类有两个或以上直接父类时称这个继…...

【快捷测试模型是否可以跑通】设置一张图片的张量形式,送入自己写的模型进行测试

文章目录 1. 1. import torch.nn as nn import torch from einops import rearrange, repeat from einops.layers.torch import Rearrange import torch.nn.functional as Fclass PreNorm(nn.Module):def __init__(self, dim, fn):super().__init__()self.norm nn.LayerNorm(…...

软考系列(系统架构师)- 2019年系统架构师软考案例分析考点

试题一 软件架构(架构风格、质量属性) 【问题1】(13分) 针对用户级别与折扣规则管理功能的架构设计问题,李工建议采用面向对象的架构风格,而王工则建议采用基于规则的架构风格。请指出该系统更适合采用哪种…...

安防视频监控系统EasyCVR视频汇聚存储平台定制化开发:新增kafka配置

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快,可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等,以及支持厂家私有协议与SDK接入,包括海康Ehome、海大宇等设备的SDK等。平台可拓展性强、…...

C++设计模式_08_Factory Method工厂方法模式

文章目录 1. “对象创建模式”模式1.1 典型模式 2. 动机(Motivation)3. 代码演示Factory Method工厂方法模式3.1 常规方法3.2 面向接口的编程3.2.1 FileSplitter1.cpp3.2.2 MainForm1.cpp 3.3 Factory Method工厂方法3.3.1 ISplitterFactory.cpp3.3.2 Ma…...

【TensorFlow1.X】系列学习笔记【基础一】

【TensorFlow1.X】系列学习笔记【基础一】 大量经典论文的算法均采用 TF 1.x 实现, 为了阅读方便, 同时加深对实现细节的理解, 需要 TF 1.x 的知识 文章目录 【TensorFlow1.X】系列学习笔记【基础一】前言线性回归非线性回归逻辑回归总结 前言 本篇博主将用最简洁的代码由浅入…...

Linux 基础操作手记三(内存篇)

Linux 基础操作手记三 释放内存虚拟机彻底无网络测试网速设置虚拟内存交换空间未使用虚拟机设置虚拟内存无法开机问题GParted - 分配内存系统盘扩容自己 释放内存 sync && echo 3 > /proc/sys/vm/drop_caches 虚拟机彻底无网络 还原默认设置,静静的等待…...

NodeJS的初使用,以及引入第三方插件和安装淘宝镜像的教程

NodeJs 命令 npm init -y 生成package.json文件npm i jquery --save–dev 开发依赖(jQuery后面还可以跟模块,可以有多个)npm i jquery --save 生产依赖npm i jquery --D 开发依赖npm uninstall jquery 卸载删除npm i 把删掉的模块,全部重新加载回来 1.介绍 1.什么是NodeJs?…...

Java读取文件的N种方法

1.概述 在这篇文章里, 我们将探索不同的方式从文件中读取数据。 首先, 学习通过标准的的Java类,从classpath、URL或者Jar中加载文件。 然后,学习通用BufferedReader, Scanner, StreamTokenizer, DataInputStream, SequenceInput…...

子类的构造与析构过程

一、简介 父类,也称基类,其构造方法和析构方法不能被继承; 子类,也称派生类,继承父类的方法和属性,但要加入新的构造和析构函数。 二、构造与析构过程 构造:先调用父类——>再调用子类 析构&…...

位运算相关笔记

位运算 Part 1:基础 左移:左移一位,相当于某数乘以 2 2 2。左移 x x x位,相当于该数乘以 2 x 2^x 2x。 右移:右移一位,相当于某数除以 2 2 2。右移 x x x位,相当于该数除以 2 x 2^x 2x。 与运算&…...

uniapp 安装 u-view 组件库

u-view 组件库安装教程:https://uviewui.com/components/install.html 注:以下使用 HBuilderx 安装 u-view 2.0 版本,不适用于其它版本。 1.安装 u-view 组件库 2、注册并登录 HBuilderx 账号,点击下载 u-view 组件库。 3、点击…...

Go 语言的成功案例:谁在使用 Go?

Go 语言,也被称为 Golang,是一门由Google开发的开源编程语言。自从2009年首次亮相以来,它在编程社区中崭露头角,并吸引了越来越多的开发者和组织。Go 以其高效的并发性、出色的性能和简单易懂的语法而闻名。在本文中,我…...

UG\NX二次开发 实时查看 NX 日志文件

文章作者:里海 来源网站:王牌飞行员_里海_里海NX二次开发3000例,里海BlockUI专栏,C\C++-CSDN博客 感谢粉丝订阅 感谢 a18037198459 订阅本专栏,非常感谢。 简介 实时查看 NX 日志文件,有助于分析保存时间等。打开WindowsPowerShell并实时获取日志文件内容的小功能。 效果 代…...

React第五十七节 Router中RouterProvider使用详解及注意事项

前言 在 React Router v6.4 中&#xff0c;RouterProvider 是一个核心组件&#xff0c;用于提供基于数据路由&#xff08;data routers&#xff09;的新型路由方案。 它替代了传统的 <BrowserRouter>&#xff0c;支持更强大的数据加载和操作功能&#xff08;如 loader 和…...

ssc377d修改flash分区大小

1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

Python实现prophet 理论及参数优化

文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候&#xff0c;写过一篇简单实现&#xff0c;后期随着对该模型的深入研究&#xff0c;本次记录涉及到prophet 的公式以及参数调优&#xff0c;从公式可以更直观…...

生成 Git SSH 证书

&#x1f511; 1. ​​生成 SSH 密钥对​​ 在终端&#xff08;Windows 使用 Git Bash&#xff0c;Mac/Linux 使用 Terminal&#xff09;执行命令&#xff1a; ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" ​​参数说明​​&#xff1a; -t rsa&#x…...

WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成

厌倦手动写WordPress文章&#xff1f;AI自动生成&#xff0c;效率提升10倍&#xff01; 支持多语言、自动配图、定时发布&#xff0c;让内容创作更轻松&#xff01; AI内容生成 → 不想每天写文章&#xff1f;AI一键生成高质量内容&#xff01;多语言支持 → 跨境电商必备&am…...

12.找到字符串中所有字母异位词

&#x1f9e0; 题目解析 题目描述&#xff1a; 给定两个字符串 s 和 p&#xff0c;找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义&#xff1a; 若两个字符串包含的字符种类和出现次数完全相同&#xff0c;顺序无所谓&#xff0c;则互为…...

自然语言处理——Transformer

自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效&#xff0c;它能挖掘数据中的时序信息以及语义信息&#xff0c;但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN&#xff0c;但是…...

Spring数据访问模块设计

前面我们已经完成了IoC和web模块的设计&#xff0c;聪明的码友立马就知道了&#xff0c;该到数据访问模块了&#xff0c;要不就这俩玩个6啊&#xff0c;查库势在必行&#xff0c;至此&#xff0c;它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据&#xff08;数据库、No…...

RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)

RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发&#xff0c;后来由Pivotal Software Inc.&#xff08;现为VMware子公司&#xff09;接管。RabbitMQ 是一个开源的消息代理和队列服务器&#xff0c;用 Erlang 语言编写。广泛应用于各种分布…...

Golang——7、包与接口详解

包与接口详解 1、Golang包详解1.1、Golang中包的定义和介绍1.2、Golang包管理工具go mod1.3、Golang中自定义包1.4、Golang中使用第三包1.5、init函数 2、接口详解2.1、接口的定义2.2、空接口2.3、类型断言2.4、结构体值接收者和指针接收者实现接口的区别2.5、一个结构体实现多…...