Linux - 进程的优先级 和 如何使用优先级调度进程

news2024/10/6 4:06:58

理解linux 当中如何做到 把一个PCB 放到多个 数据结构当中

在Linux 当中,一个进程的 PCB 不会仅仅值存在一个 数据结构当中,他既可以在 某一个队列当中,又可以在 一个 多叉树当中。

队列比如 cpu 的 运行队列,键盘的阻塞队列等等的双线链表当中。

而多叉树就本篇博客需要阐述的 进程优先级了。

如何实现的其实也很简单,就是在一个 PCB 结构体对象当中,不仅仅只有 双链表的 prev 前序结点指针和 next 后继结点指针;还有 多叉树当中的 比如 parent 父亲结点指针,和各个孩子的指针。这时,因为链式的数据结构管理各个 进程的 PCB 结构体对象也是通过这个结构体对象的 指针来实现管理的。所以,我们才说一个结点就可以插入到 一个双向链表当中,又可以插入到 一个多叉树当中。

下面,简单实现一个 PCB 结构体的 demo,来理解:

如上所示,通过在 PCB 结构体当中,内嵌一个 双链表结点的结构体,来维持 这个PCB在某一个 双链队列当中的存储位置。

这样,就可以通过一个 PCB 来找到这个 PCB 所在队列的所以的PCB 了,也就相当于是把 这个PCB链接到某一个队列当中了。

但是,这样的话有一个问题,就是,我可以找到 存在与 各个 PCB 对象当中的 link 结构体对象在各个 PCB 当中存储的位置,但是,如果我们想要访问整个 PCB对象的话,需要拿到 PCB 对象的地址(存储 PCB 对象起始位置的 PCB类型的结构体指针)。

所以,结合上述 demo,我们用以下方式来 计算出 link 和 link所在PCB对象当中的 地址偏移量,然后 得到 PCB 对象的起始地址
 

(task_struct*)((char*)head - (char*)&(task_struct*)0->link) -> other

上述代码就可以拿到 PCB 的起始地址,然后访问 PCB 当中的 其他 (other)属性。

怎么做到的呢?我们来一步一步看:

(上述的 head 和 &(task_struct*)0->link 要强转成 char* 类似的,以为此时是以 数字的方式来看待的,而不是指针,我们是为了计算出偏移量。但是上述为了图片的 宽度没有写上。)画个图来 理解:

 利用 0 开始 的 PCB 结构体指针,计算出 link 距离 PCB 起始位置的 偏移量(相对距离)。

 像上述是一个PCB 的访问方式,当然,一个队列当中会有很多个,不同种类的 PCB 对象,那么其中的 link 所在位置也是不一样的,但是都可以同种上述的方式来,计算出当前PCB当中 link 相对于 PCB 起始位置的偏移量。

 进程的优先级

因为资源是有限的,进程有很多个,所以,注定了进程之间是竞争关系。

操作系统必须要保证 各个进程之间必须要 良性竞争。 所以,制定了优先级,对于各个进程之间,对于资源的访问,谁先谁后,由进程各自的优先级决定。

cpu资源分配的先后顺序,就是指进程的优先权(priority)

优先权高的进程有优先执行权利。配置进程优先权对多任务环境的linux很有用,可能改善系统性能。
还可以把进程运行到指定的CPU上,这样一来,把不重要的进程安排到某个CPU,可以大大改善系统整体性能。
 

如果因为调度算法不合理,优先级设定算法不合理,就会导致某些进程长时间得不到CPU资源,某些进程的代码长时间得不到推进。造成了该进程的饥饿问题

 这种饥饿问题,在用户体验上看来就是,某个进程卡死了,得不到响应。就像在 windows 当中,可能遇到过其他进程都没事,但是某一个进程卡死了,提示无法响应,此时你会有两个选项:结束进程或者是再等等。


我们可以使用 ps -l 查看当前终端下,用户启动的 进程,但是这个命令不能查看单独由其他终端启动的进程。如果想查看的话,可以再多加一个 -a 选项查看用户启动的全部进程

 

UID 的解释:因为计算机只认识数字,所以,区分各个 用户也是使用数字来区分的,UID 就是各个用户独有的ID,就像身份证号一样,在这个操作系统当中,一个用户的这一个 ID 是独有的。

 PRI也还是比较好理解的,即进程的优先级,或者通俗点说就是程序被CPU执行的先后顺序,此值越小进程的优先级别越高。

 

 NI 的解释:因为 操作系统当中的调度器,要更具当前操作系统的需求,或者是用户的需求,要给根据算法来修改某一个进程的 优先级,但是原来的优先级是 调度器计算出来非常合理的优先级,也就是 PRI 是刚开始计算出来最合理的优先级,所以这个 PRI 优先级是要保存的;所以,如果调度器要修改优先级的话修改的不是 PRI,而是使用 PRI(new)=PRI(old)+nice 。从而使用 PRI(new)作为现在 进程所使用的优先级。当 此时 操作系统和用户没有再需求之后,就会使用 原本的 PRI 优先级。

虽然都是按照  PRI(new)=PRI(old)+nice  这个公式来进行修改的,但是 PRI(old)是不变的,默认一直都是 80

这样,当nice值为负值的时候,那么该程序将会优先级值将变小,即其优先级会变高,则其越快被执行所以,调整进程优先级。

需要强调一点的是,进程的nice值不是进程的优先级,他们不是一个概念,但是进程nice值会影响到进程的优先级变化。

那么,既然优先级可以被调整,那么是不是就以为这个,我们可以把一个 进程的nice 值,调的非常的低,使得这个进程优先级很高,一直被调度?答案是不行的。

Linux不想过多的让用户参与到 优先级的调整当中,只能在对应的范围之内膝盖 nice 值。超过范围,只能给范围的极值作为值返回,不能超过极值。

在Linux下,就是调整进程nice值nice其取值范围是-20至19,一共40个级别。

 利用 top 修改nice的同时修改 进程的 PRI(new)

 top 是任务管理器,当我们在 top 窗口当中,按下 r 键,就可以执行 renice 命令:

 

此时它提示我们输入 某个进程 的PID,我们就输入 我们自己写的 死循环进程的PID:

 

回车之后,就会提示我们,要修改的nice值为多少,我们就可以再 上述所说的 nice 的区间当中给值,就算是 超出了,也就给出对应分为的极值。比如我们现在给出 100:
 

回车之后就会修改 nice 值:
 

因为 nice 最大就是 19,所以,此时就是修改到了 99。

 Linux当中 cpu 当中调度不同优先级的做法

 在 cpu 当中有一个运行队列,这些队列当中的使用指针的方式排列着 处于运行状态的 进程的PCB指针。但是,这些进程的 优先级有大有小,cpu 是如何调度其中的 进程的呢?

其实在这个运行队列当中,会存储两个 存储 PCB指针的 指针数组,这个两个数组一般的大小是 140 个元素,前 0-99 个元素存储的是其他进程的 task_struct指针,在后面的 [100 - 139 )这个刚好 40 个元素 的指针就是存储的是 我们可以修改的 nice 指针的数目。

我们用这 40 个元素做例子:

我们可以修改到的 优先级范围就在 [60 , 99) 这个区间当中,这个区间就刚好映射到了 [100, 139 ) 这个指针数组的下标。那么我们就可以根据优先级,映射到 这个指针数组下标。类似这样的结构,如下图所示:
 

 利用这种 类似于 开散列式的哈希表来 实现,这种结构非常像 哈希桶。

cpu只需要在左边的指针数组当中 按照下标来一个调用有这个 task_struct * 指向的单链表来依次调用其中的 进程。

如果后续需要添加进程,只需要按照 这个进程的 优先级,插入到对应的 指针数组 元素指向的 单链表尾插即可。


上述描述的是running 这个指针数组,当 运行队列当中只有 running 这个指针数组之时,那么就是按照上述的方式进行操作的。

但是,在LInux 当中还有一个 waiting 指针数组,在上述,我们说过,在后序插入的 进程,是直接在 running 维护的对应的单链表当中尾插的。但是现在有了 waiting指针数组,就不在 running 当中插入了,直接在 waiting 指针数组当中插入即可。这个 waiting 指针数组的存储结构 和 running 是一样的。

而且,不仅仅有上述两个 指针数组,还有两个 二级指针,指向这个两个数组。实际上,cpu 不是按照 running数组的首元素地址开始执行程序,而是按照 这个 指向 running数组的 二级指针来执行进程。当 running 当中的进程执行完之后,只需要 交换 指向 running数组 和 waiting数组 两个数组的 两个二级指针指向即可。就是把 两个二级指针指向的内存做交换。

 

向上述所举的例子,run 这个二级指针,一定指向的是 正在执行的队列;而 wait 二级指针指向的是 还没有新插入的正在等待的队列。


 但是,现在还有一问题,怎么知道 run 指向的队列已经执行完了呢?

就只能取遍历这个指针数组,各个指针元素是否指向空。

 但是,这种方式有点满,所以,我们使用 位图 来映射 这个队列的每一个位置是否为空。使用 位图就可以 实现近乎 O(1)的时间复杂度来找到 从当前查找位置开始,最近一个 不为空的 单链表位置。

具体位图,可以看一下博客介绍:

C++ - 位图 - bitset 容器介绍_chihiro1122的博客-CSDN博客

 这种使用位图来实现查找 最近的 队列不为空的算法,被称之为 --- Linux 内核 当中的 O(1)调度算法。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1136717.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

性能测试用例和测试结果

性能测试用例和测试结果 一 核心业务功能的TPS测试1.1 登录接口测试用例1.2 进入首页接口测试用例1.3 添加购物车接口测试用例1.4 结算和下订单接口测试用例1.5 系统资源使用率1.6 单接口测试中一个测试的各个成员接口要单独做性能统计 二 业务流程(多接口组合&…

word行内插入mathtype 公式后行距变大解决办法

现象 word行内插入mathtype 公式后行距变大 解决方法 选中要进行操作的那些行,依次单击菜单命令“格式→段落”,打开“段落”对话框;单击“缩进和间距”选项卡,将间距的“段前”和“段后”都调整为“0行”;将“如果…

中国密码算法与NIST标准对比

1. 引言 NIST定义AES为标准的对称密钥加密算法。但NIST被指出可能在加密算法中添加NSA后门。为此,在中国,ShāngM (SM) 系列密码算法,作为TLS 1.3集成和无线认证的备选方案: SM2:定义了认证(签名&#xf…

薅!语雀致歉送6个月会员;万字教程讲透AI视频生成;提示词14个黄金设计法则;吴恩达AI职业规划指南 | ShowMeAI日报

👀日报&周刊合集 | 🎡生产力工具与行业应用大全 | 🧡 点赞关注评论拜托啦! 🔥 讯飞发布星火认知大模型 V3.0,并推出多款大模型产品 10月24日,科大讯飞正式发布「星火认知大模型V3.0」&#…

layui框架实战案例(23):select编辑回显内容及事件调用

layUI框架实战案例系列文章 layui框架实战案例(21):layui上传的哪些事(layui.upload组件、 file文件域、php后台上传)layui框架实战案例(20):常用条件判断和信息展示技巧(图片预览、动态表格、短信已读未读、链接分享、信息脱敏、内置框架页)layui框架实…

【经验分享】openGauss容灾集群搭建

gs_sdr命令代码解读 背景 openGauss推出了容灾架构,相比之前的一个集群主从架构,而容灾架构是两个集群间的数据同步。为了更深入了解其原理,本文试图通过阅读gs_sdr命令相关的代码来学习下相关的各种操作。 1.容灾搭建过程可以参考&#xf…

Ragnar-lothbrok 靶机

Ragnar-lothbrok 信息搜集 存活检测 详细扫描 后台网页扫描 网站信息搜集 secret “秘密”网页 将密文保存到 password.txt 此页面使用了 wordpress CMS 疑似用户 ragnar wpscan 也爆破出了用户 ragnar wpscan --url http://10.4.7.155/wordpress/ --enumerate u 密码获…

Node.js中的单线程服务器

为了解决多线程服务器在高并发的I/O密集型应用中的不足,同时避免早期简单单线程服务器的性能障碍,Node.js采用了基于"事件循环"的非阻塞式单线程模型,实现了如下两个目标: (1)保证每个请求都可以…

外汇天眼:获利数倍、财务自由不是梦? 小心网络投资诈骗4阶段!

近年来网络投资愈来愈热络,我们经常看到有人因做加密货币、外汇交易而致富的报道,并开始寻找可以获利的投资机会与渠道。 然而,诈骗集团也注意到这个趋势,因此透过假冒经纪商或开设黑平台等方式,伺机获取不法所得。 有…

Github.io个人主页模板(进阶版)

网上很多博客感觉是有点Outdate了,而且通用性不强,希望这篇博客能给你帮助。 【保姆级教程】手把手教你用github制作学术个人主页(学者必备)_github个人主页模板-CSDN博客 【GitHub】用Jekyll模板快速制作github.io学术主页 - 知…

JVS低代码表单引擎之文本框的强大作用,建议收藏!

表单是低代码最基础的数据输入的方式,其中文本框是配置话表单的最基础的业务能力组件之一,主要用于收集和展示用户录入的文本类的信息,例如名称、地址、描述说明等等。 那么我们接下来分几个方面分别对文本框的使用进行讲解。 基础功能 拥有…

初识Java 16-1 字符串

目录 字符串的常量和变量 不变的String常量 String变量 重载的和更快的StringBuilder 容易忽略的递归现象 对字符串的操作 格式化输出 System.out.format() Formatter类 格式说明符 Formatter转换 String.format() 新特性:文本块 本笔记参考自&#xff…

Creaform形创HandySCAN MAX l Elite三维扫描仪便携式3D测量解决方案

CASAIM中科院广州电子智能制造事业部连续多年荣获形创Creaform战略级代理商证书。战略级代理商是形创Creaform最高级别的合作伙伴。 2023年CASAIM中科院广州电子智能制造事业部的形创Creaform战略级代理商证书: Creaform 形创是便携式三维测量解决方案和工程服务领…

使用mac自带VNC公网远程控制macOS

公网远程控制macOS【使用mac自带VNC】 文章目录 公网远程控制macOS【使用mac自带VNC】前言1. 测试局域网内远程控制1.1 macOS打开屏幕共享1.2 测试局域网内VNC远程控制 2. 测试公网远程控制2.1 macOS安装配置cpolar内网穿透2.2 创建tcp隧道,指向5900端口 3. 测试公网…

人工智能的发展方向:探索智能未来的无限可能

原创 | 文 BFT机器人 人工智能,简称AI,是一门专注于研究计算机如何能像人类一样思考、学习和解决问题的科学。它的创造初衷是构建一个智能系统,能模仿、模拟甚至实现人工智能的各种功能和行为,随着科技的持续进步,人工…

TSINGSEE青犀智能分析网关裸土覆盖算法如何做到防范山体滑坡?

在雨水季节,特别是山区,十分容易发生山体滑坡现象,会导致山村、铁路、公路、房屋、甚至城镇被冲毁,造成严重的人员伤亡和财产损失。而TSINGSEE青犀智能分析网关裸土覆盖算法是一种利用图像处理技术来评估裸露土壤面积和裸露程度的…

VMware打开共享虚拟机后找不到/mnt/hgfs/文件夹,以及不能拖拽/复制粘贴等操作,ubuntu不能安装VMware tools

问题原因 我的问题出现原因是,安装ubuntn虚拟机的时候VMware tools没有安装好,需要重新安装,但安装选项是暗的,不能操作。 类似这种情况,虚拟机开启时也是,因为我虚拟机已经装好了,开启时是亮…

【JAVA】:万字长篇带你了解JAVA并发编程【二】

目录 【JAVA】:万字长篇带你了解JAVA并发编程【二】3. 线程池池化技术线程池的概念与作用什么是线程池?优点 Executor框架Executor框架组成部分工作任务抽象接口和类 线程池的生命周期非核心线程和核心线程ThreadPoolExecutor线程池的工作流常见的线程池…

快速解决msvcp140.dll丢失问题的5个方法,轻松修复dll问题

在计算机使用过程中,我们经常会遇到一些错误提示,其中之一就是“msvcp140.dll丢失”。那么,msvcp140.dll究竟是什么?它丢失需要怎么修复呢?本文将从多个角度对这一问题进行详细解析。 一、msvcp140.dll是什么 msvcp14…

C/C++输出整数 2020年9月电子学会青少年软件编程(C/C++)等级考试一级真题答案解析

目录 C/C输出整数 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序编写 四、程序说明 五、运行结果 六、考点分析 C/C输出整数 2020年9月 C/C编程等级考试一级编程题 一、题目要求 1、编程实现 输入四个整数,把输入的第三、第四个整数输出…