Linux --进程优先级

article/2025/6/6 4:35:10

概念

  什么是进程优先级,为什么需要进程优先级,怎么做到进程优先级这是本文需要解释清楚的。

  优先级的本质其实就是排队,为了去争夺有限的资源,比如cpu的调度。cpu资源分配的先后性就是指进程的优先级。优先级高的进程有优先执行的,配置进程优先级对多任务环境的Linux很有用,可以改善系统的性能。在Linux中进程的PCB也就是task_struct中优先级属性是有几个int类型的数字来表示的,数字越小优先级越高。这里我们可以查看一个进程的优先级和修改。我们用ps -l指令可以看到以下几个数据

UID : 代表执⾏者的⾝份
PID : 代表这个进程的代号
PPID :代表这个进程是由哪个进程发展衍⽣⽽来的,亦即⽗进程的代号
PRI :代表这个进程可被执⾏的优先级,其值越⼩越早被执⾏
NI :代表这个进程的nice值
  
  PRI也还是⽐较好理解的,即进程的优先级,或者通俗点说就是程序被CPU执⾏的先后顺序,此
值越⼩进程的优先级别越⾼ 。 那NI呢?就是我们所要说的nice值了,其表⽰进程可被执⾏的优先级的修正数值 PRI值越⼩越快被执⾏,那么加⼊nice值后,将会使得PRI变为:PRI(new)=PRI(old)+nice 这样,当nice值为负值的时候,那么该程序将会优先级值将变⼩,即其优先级会变⾼,则其越快被执⾏所以,调整进程优先级,在Linux下,就是调整进程nice值 nice其取值范围是-20⾄19,⼀共40个级别。这里的PRY(old)其实是默认初始PRI的意思。
  ⽤top命令更改已存在进程的nice: top,进⼊top后按“r”‒>输⼊进程PID‒>输⼊nice值

  

  这里可以看到,PRI为39 NI值为19,这是我修改以后的数值,原本是PRI 20 NI 0,即使我输入修改100但是最后值修改了19,说明修改NI值是有范围的 ,这是为了进程调度尽量公平,不会出现个别极端进程,为什么是在这40的范围内后续我们会讲到。

进程切换

  有了优先级就是为了在进程切换的时候进行排序,那么什么是进程切换?进程切换的核心其实就是保存上下文数据恢复上下文数据,那么什么是上下文数据,容我慢慢叙说。一个进程被被cpu调度的时候,此时它的PCB就是现在调度队列的当前节点,在CPU内部有一套寄存器来储存代码和数据,其中的eip来储存当前执行指令的下一地址,ir存储的是当前需要执行的指令,控制器先ir读指令执行,执行完毕又会反馈给eip寄存器。此时储存在寄存器中的代码和数据就是上下文数据。当前进程的时间片到了即将被切换的时候,它会将上下文数据储存到PCB中的一个tss_struct结构体中,方便下次切换回来的时候能够知道上一次运行到了哪里,恢复寄存器中的数据,每个程序在进程切换的时候都需要做这个事情,因为寄存器只有一套,这种行为是对进程代码数据运行的一种保护,如果不做保护就无法进行调度与切换。

  这里可以参考Linux0.11的内核代码发现上下文数据确实是保存在tss之中,但是在现在的内核中由于保护算法已经过于复杂了,没有十章八章难以叙述,所以而且不方便观察

Linux真实调度算法

  说了这么多优先级的本质还是为了更好的了解Lniux调度算法。这个算法并不是简单的FIFO调度,cpu在调度进程时会在一个runqueue结构体中选择需要调度的进程,这个runqueue主要由一个有两个元素queue结构体数组,两个指向queue结构体数组的指针,*active和*expored即活跃的和过期的,以下用示意图说明。

  

  我们可以看到这这两个数组的元素的结构体时由一个int 类型的nr_active,和一个有五个元素int类型的bitmap数组组成的。*active和*expored指针分别指向这两个数组元素,cpu调度时只会从活跃指针这个结构体中的queue队列来调度进程,这个队列通常前一百位是不用的,而后四十位就是对应我们上面所提到的优先级范围,40这个范围就是因为队列中只有四十个位置是储存进程的。这个队列每个元素下又挂着一个哈希桶,所以每个相同优先级的进程都会被挂在同一个桶中,调度的时候按照队列先进先出的规则被调度,当这个优先级桶的元素空了cpu才会调度下一个优先级的进程。其中这里的nr_active是一个计数器,记录当前队列中还有多少个进程,bitmap是为了提高cpu调度效率而存在的,它用5*32个比特位来表示当前调度queue队列中哪个优先级有进程再去这个地方调度进程,而不是进行遍历队列查找再调度。过期队列上放置的进程,都是时间⽚耗尽的进程和新插入的进程,当活动队列上的进程都被处理完毕之后,对过期队列的进程进⾏时间⽚重新计算。active指针永远指向活动队列, expired指针永远指向过期队列, 可是活动队列上的进程会越来越少,过期队列上的进程会越来越多,因为进程时间⽚到期时⼀直都存在的,所以在合适的时候交换active指针和expired指针的内容,就相当于有具有了⼀批新的活动进程。这个合适的时候就是当活跃进程nr_active计数器为0的时候,此时两个两个队列就会被调换开始新一轮的调度。注意结束的进程是不会进入过期队列的,而是会被父进程接管并释放。

   在系统当中查找⼀个最合适调度的进程的时间复杂度是⼀个常数,不随着进程增多⽽导致时间成 本增加,我们称之为进程调度O(1)算法!Linux中的内核调度算法就是进程调度O(1)算法。

  顺便提到一点Linux中的task_struct中的链式结构并不是和普通双链表那样将节点和属性放在一起,它的链表节点中只有next节点和prev节点,然后在task_struct中和其他属性一起储存。这样做的好处是能够让一个task_struct在多个队列(调度和阻塞)中存在,而不需要将相同的进程属性放在不同的链表之中再链接。如图所示

 

补充 

  那么有的同学会问了只有链表节点如何访问数据,每个数据类型的偏移量相对于结构体指针是固定的,我们可以通过链表节点的地址和偏移量来找到当前结构体指针再访问其他的数据。我们可以通过offseto这个宏来获得该成员相对于0地址的偏移。

#define offsetof(type, member) ((size_t)&(((type *)0)->member))

这里有一个代码可以方便大家理解具体过程

#include <iostream>#define offsetof(type, member) ((size_t)&(((type *)0)->member))
using namespace std;int main()
{struct A{int a;int b;float c;double d;};A instanceA; // Renamed variable to avoid conflict with struct namecout << " 结构体A的地址 : " << &instanceA << endl;cout << " 成员a的地址  :" << &instanceA.a << " 偏移量 :" << offsetof(A, a) << endl;cout << " 成员b的地址  :" << &instanceA.b << " 偏移量 :" << offsetof(A, b) << endl;cout << " 成员c的地址  :" << &instanceA.c << " 偏移量 :" << offsetof(A, c) << endl;cout << " 成员d的地址  :" << &instanceA.d << " 偏移量 :" << offsetof(A, d) << endl;return 0;
}

  我们可以看到两次运行的各个成员地址都不一样,但是偏移量都是相同的 

  然后我们就可以通过这样的方法来找到对象本身从而访问其他的数据

int main() {A instanceA;int* pB = &instanceA.b;A* pStruct = (A*)((char*)pB - offsetof(A, b));cout << "instanceA 地址: " << &instanceA << endl;cout << "通过成员b地址和偏移量得到的结构体地址: " << pStruct << endl;return 0;
}


http://www.hkcw.cn/article/DlnhXDOLwF.shtml

相关文章

Web后端快速入门(Maven)

Maven是apche旗下的一个开源项目&#xff0c;是一款用于管理和构建java项目的工具。 开源项目&#xff1a;Welcome to The Apache Software Foundation. Maven的作用&#xff1a; 依赖管理&#xff08;方便快捷的管理项目依赖的资源&#xff0c;避免版本冲突问题&#xff09…

工业透明材料应力缺陷难检测?OAS 软件应力双折射案例来解决

应力双折射案例分析 简介 应力是物体内部力的分布状态&#xff0c;反映了物体材料中相邻部分之间的相互作用力。对于透明各向同性光学元件而言&#xff0c;在应力作用下会表现出暂时的双折射特性&#xff0c;这种特性使得光线在元件内部传播时&#xff0c;会分解为两束具有不同…

C# winform教程(二)----button

一、button的使用方法 主要使用方法几乎都在属性内&#xff0c;我们操作也在这个界面 二、作用 用户点击时触发事件&#xff0c;事件有很多种&#xff0c;可以根据需要选择。 三、常用属性 虽然属性很多&#xff0c;但是常用的并不多 3.常用属性 名称内容含义AutoSize自动调…

yzncms系统验证码关闭以及验证码后台配置功能

问题&#xff1a;yzncms系统的验证码如何关闭&#xff0c;以及怎么在后台配置参数呢&#xff1f; 回答&#xff1a;目前yzncms系统的验证码是没有后台配置功能的&#xff0c;也没有关闭功能&#xff0c;只能靠自己在源码里修改配置参数。 不过&#xff0c;不要着急&#xff0…

如何制定数字化转型策略:从理念到落地的全面指南

在当今快速变化的商业环境中&#xff0c;数字化转型&#xff08;DX&#xff09;已成为企业保持竞争力和实现可持续发展的关键。然而&#xff0c;很多企业在推进数字化转型时常常感到无从下手。今天小编就来为大家梳理一下如何制定一套科学且可行的数字化转型策略&#xff0c;助…

阿姆达尔定律的演进:古斯塔夫森定律

前言 在上一篇文章《使用阿姆达尔定律来提升效率》中提到的阿姆达尔定律前提是假设问题的规模保持不变&#xff0c;并且给定一台速度更快的机器&#xff0c;目标是更快地解决问题。然而&#xff0c;在大多数情况下&#xff0c;这并不完全正确。当有一台更快的机器时&#xff0…

Qt 仪表盘源码分享

Qt 仪表盘源码分享 一、效果展示二、优点三、源码分享四、使用方法 一、效果展示 二、优点 直观性 数据以图表或数字形式展示&#xff0c;一目了然。用户可以快速获取关键信息&#xff0c;无需深入阅读大量文字。 实时性 仪表盘通常支持实时更新&#xff0c;确保数据的时效性。…

吞咽与营养并重:进行性核上性麻痹的饮食之道

进行性核上性麻痹是一种罕见的神经系统变性疾病&#xff0c;患者常出现吞咽困难、肢体运动障碍等症状&#xff0c;合理饮食对改善患者营养状况、延缓病情发展至关重要。以下为进行性核上性麻痹患者量身定制的健康饮食方案。 ​患者饮食需遵循 “细软易消化、均衡营养、少食多餐…

leetcode hot100 链表(二)

书接上回&#xff1a; leetcode hot100 链表&#xff08;一&#xff09;-CSDN博客 8.删除链表的倒数第N个结点 class Solution { public:ListNode* removeNthFromEnd(ListNode* head, int n) {ListNode* currhead;int len0;while(curr){currcurr->next;len;}int poslen-n…

结构性设计模式之Composite(组合)

结构性设计模式之Composite&#xff08;组合&#xff09; 摘要&#xff1a; Composite&#xff08;组合&#xff09;模式通过树形结构表示"部分-整体"层次关系&#xff0c;使得用户能够统一处理单个对象和组合对象。该模式包含Component&#xff08;组件接口&#x…

【Typst】4.导入、包含和读取

概述 上节概述了Typst脚本的基础语法&#xff0c;在此基础上&#xff0c;本节介绍Typst文件的导入、包含和读取的内容。你将可以更简单灵活的组织你的文件内容。 系列目录 1.Typst概述2.Typst标记语法和基础样式3.Typst脚本语法4.导入、包含和读取5.文档结构元素与函数6.布局…

深入解析C++引用:从别名机制到函数特性实践

1.C引用 1.1引用的概念和定义 引用不是新定义⼀个变量&#xff0c;而是给已存在变量取了⼀个别名&#xff0c;编译器不会为引用变量开辟内存空间&#xff0c;它和它引用的变量共用同⼀块内存空间。比如四大名著中林冲&#xff0c;他有一个外号叫豹子头&#xff0c;类比到C里就…

【vue+ts】找不到模块“./App.vue”或其相应的类型声明

报错&#xff1a;找不到模块“./App.vue”或其相应的类型声明。 原因&#xff1a;typescript只能理解.ts文件&#xff0c;无法理解.vue文件。 解决&#xff1a;在src/env.d.ts下添加&#xff1a; /// <reference types"vite/client" /> // 三斜线引用告诉编译…

HTTP Error 400 Bad request 问题分析解决

文章目录 1.问题描述&#xff1a;2.异常信息如下&#xff1a;3.分析异常信息&#xff1a;4.总结&#xff1a; 1.问题描述&#xff1a; 前端保存老是报错HTTP ERROR 400 Bad Request。经过异常分析得出是前端传参导致的后端框架的验证拦截&#xff0c;包的错误。 2.异常信息如下…

数据库的操作

1.查看数据库 show databases; 2.库的创建 create database [IF NOT EXITS] db_name [creat_specification];[]内的是可选选项&#xff0c;IF NOT EXIT表示如果数据库名为db_name的数据库存在就创建数据库&#xff0c;否则就不创建&#xff0c;creat_specification是创建的特…

IP话机和APP拨打电话的区别

‌IP话机和IP电话App&#xff08;如Zoom Phone、Microsoft Teams、Skype等&#xff09;均基于互联网协议&#xff08;VoIP&#xff09;技术实现通话&#xff0c;但在硬件形态、使用场景、功能侧重等方面存在显著差异。以下是主要区别&#xff1a; 1. 硬件形态与部署 IP话机 物…

el-select 实现分页加载,切换也数滚回到顶部,自定义高度

el-select 实现分页加载&#xff0c;切换也数滚回到顶部&#xff0c;自定义高度 1.html <el-form-item label"俱乐部&#xff1a;" prop"club_id" label-width"120px"><el-select :disabled"Boolean(match_id)" style"w…

帝可得- 人员管理

一.需求说明 人员管理业务流程如下&#xff1a; 登录系统&#xff1a; 首先&#xff0c;后台管理人员需要登录到帝可得后台管理系统中。 新增工作人员&#xff1a; 登录系统后&#xff0c;管理人员可以新增工作人员&#xff0c;包括姓名、联系方式等信息。 关联角色&#xf…

【Java Web】7.事务管理AOP

&#x1f4d8;博客主页&#xff1a;程序员葵安 &#x1faf6;感谢大家点赞&#x1f44d;&#x1f3fb;收藏⭐评论✍&#x1f3fb; 文章目录 一、事务管理 1.1 事务回顾 1.2 Spring事务管理 1.3 事务进阶 rollbackFor propagation 二、AOP 2.1 AOP概述 2.2 AOP快速入门…

Matlab实现LSTM-SVM回归预测,作者:机器学习之心

Matlab实现LSTM-SVM回归预测&#xff0c;作者&#xff1a;机器学习之心 目录 Matlab实现LSTM-SVM回归预测&#xff0c;作者&#xff1a;机器学习之心效果一览基本介绍程序设计参考资料 效果一览 基本介绍 代码主要功能 该代码实现了一个LSTM-SVM回归预测模型&#xff0c;核心流…