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

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

理解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)调度算法。

总结

我们所看到的  各种外设,硬件设备,进程试图访问,或者使用这些外设之时,都是要在各种队列当中进行排队的。因为 这些外设,硬件设备,是少量的,而进程动不动就几百个,是很多的,这也就导致了 进程之间要竞争,要排队。

所以,操作系统为了能更好的管理 进程 之间的运行,就引入了优先级,让进程之间合理竞争相关资源。因为 各个资源是不能做到并发执行的,但是因为 cpu 计算速度很快,可以用一些调度算法,结合优先级做到 用户看上去是很多进程在同时运行一样。

各种资源,在各个进程使用期间是 独享的,并不是多个进程占用同一资源。在多进程运行期间互不干扰。进程在设计理念之上,就是 在自己运行之上不能影响到 其他进程的运行,这样是进程的独立性

如果在不考虑多核cpu的情况下,多个进程在多个CPU下分别,同时进行运行,这称之为并行
,这个称之为并行

同时,如果此时只有一个 cpu ,在一段时间之内,很多个进程都得到的执行,或者实现完毕,这个过程称之为并发

当然,为了防止某一个进程一直占用cpu,所以,一个进程还有一个时间片的概念,只允许一个进程在规定的时间之内占用时间片。

如果一个进程的时间片到了,那么这个进程就会排到下一个 等待队列当中,等到cpu处理下一轮的 进程队列。

这也是 Linux 在处理进程队列这件事情之上的 优雅处理。使得后序链入的进程,只能在当前cpu正在执行 的运行队列当中的进程全部执行完,才会执行下一个队列当中的进程,而在cpu 处理当前队列的 进程之时,在此期间链接上来的 进程,只能链接到 等待队列当中。

 

相关文章:

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

理解linux 当中如何做到 把一个PCB 放到多个 数据结构当中 在Linux 当中,一个进程的 PCB 不会仅仅值存在一个 数据结构当中,他既可以在 某一个队列当中,又可以在 一个 多叉树当中。 队列比如 cpu 的 运行队列,键盘的阻塞队列等等…...

支持控件drag和click

在 MouseDown 事件触发 DoDragDrop 拖拽操作时,Click 事件通常无效,因为 DoDragDrop 方法会捕获鼠标事件并等待拖拽操作完成。 有一个简单地思路解决这个问题 当MouseDow时,触发定时器,延迟100s定时器到时后,进入dra…...

AIR101 LuatOS LVGL 显示多个标签例程

屏幕资料 AIR101与屏幕连接 PC端仿真环境合宙官方PC端版本环境搭建教程 PC电脑仿真 -- sys库是标配 _G.sys require("sys") sys.taskInit(function()local cnt0lvgl.init(480,320)--lvgl初始化local cont lvgl.cont_create(nil, nil);-- lvgl.cont_set_fit(cont, …...

Istio实战(七)- Bookinfo 部署

1. Istio Bookinfo示例 1.1 部署Bookinfo # kubectl apply -f /apps/istio/samples/bookinfo/platform/kube/bookinfo.yaml -n hr1.2 确认Bookinfo已经部署正常 先确认以下pod和service已经被正确创建 # kubectl get pods -n hr NAME READY …...

出差学小白知识No5:|Ubuntu上关联GitLab账号并下载项目(ssh key配置)

1 注冊自己的gitlab账户 有手就行 2 ubuntu安装git ,并查看版本 sudo apt-get install git git --version 3 vim ~/.ssh/config Host gitlab.example.com User your_username Port 22 IdentityFile ~/.ssh/id_rsa PreferredAuthentications publickey 替换gitl…...

FL Studio21.2中文版多少钱?值得下载吗

水果,全称Fruity Loop Studio,简称FL Studio。是一款全能的音乐制作软件,经过二十多年的演化更迭,其各项功能非常的先进。其开创性的Pat\song模式,也为初学者的学习提供了便利。那么水果音乐制作软件需要多少钱呢&…...

软考系统架构师知识点集锦三:软件架构设计

一、考情分析 二、考点精讲 2.1软件架构的概念 2.1.1什么是架构(暂无定论) 架构设计就是需求分配,即将满足需求的职责分配到组件上。 软件架构风格是描述某-特定应用领域中系统组织方式的惯用模式。架构风格定义-个系统家族,即一个体系结构定义一个词汇表和一组约…...

docker - window Docker Desktop升级

文章目录 前言docker - window Docker Desktop升级 前言 如果您觉得有用的话,记得给博主点个赞,评论,收藏一键三连啊,写作不易啊^ _ ^。   而且听说点赞的人每天的运气都不会太差,实在白嫖的话,那欢迎常来…...

Element UI + Vue 新增和编辑共用表单校验无法清除问题(已解决)

问题描述 在新增和编辑过程中大部分情况下 两个表单是一致的,而且编辑也有回显需要,所有绝大多数情况下 都是一个表单两个用处,但是随之而来出现了一个无法清除校验的问题,在先点击编辑后再点击新增会出现校验红字: …...

FL Studio21最新中文汉化解锁版,2024怎么激活FL Studio

FL Studio2024最新中文汉化解锁版是一款功能强大的数字音频工作站(DAW),它广泛应用于音乐创作和音乐制作领域。在使用FL Studio时,购买正版软件是否有必要呢?本文将详细探讨FL Studio的功能特点以及正版软件的重要性。…...

Mac怎么清理磁盘空间?释放Mac磁盘空间有效方法

相信很多使用macOS系统的小伙伴都收到过提示“磁盘空间已满”消息,尤其是采用SSD固态硬盘的MacBook系列,120G的硬盘空间本就捉襟见肘,使用一段时间后,即使自己没有存放很多大文件, Mac的磁盘很快就满了。那么&#xff…...

论文阅读(一)城市干道分段绿波协调控制模型研究

[1]酆磊,赵欣,李林等.城市干道分段绿波协调控制模型研究[J].武汉理工大学学报(交通科学与工程版),2021,45(06):1034-1038. 主要内容:该文介绍了基于绿波带宽和关联度的城市干道分段绿波协调控制模型。通过将主干道划分为不同子区域,并根据路段特点进行精准化控制,实现了分段…...

k8s 部署nginx前端

1.构建docker镜像,k8s拉取镜像运行docker自己安装 [rootmaster1 ~]# docker pull nginx:1.24.0 [rootmaster1 ~]# mkdir k8s-nginx [rootmaster1 ~]# cd k8s-nginx [rootmaster1 k8s-nginx]# vim nginx.conf server_tokens off;server {listen 8010; #web访…...

ClickHouse UDF 官方示例Example报错解决方案

目录 一、环境版本二、官方示例三、解决方案1.Python脚本运行缺少权限2. 缺少Python3运行环境 四、参考借鉴 一、环境版本 环境版本docker clickhouse22.3.10.22 docker pull clickhouse/clickhouse-server:22.3.10.22二、官方示例 官网文档 test_function使用 XML 配置创建…...

eval()函数的用法,计算字符串中的值,模板字符串进行计算

eval函数的定义: eval() 函数计算 JavaScript 字符串,并把它作为脚本代码来执行。 如果参数是一个表达式,eval() 函数将执行表达式。如果参数是Javascript语句,eval()将执行 Javascript 语句。 let a1 10; let a2 20; let calcu…...

leetcode第80题:删除有序数组中的重复项 II

题目描述 给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使得出现次数超过两次的元素只出现两次 ,返回删除后数组的新长度。 不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。 …...

【Docker】Docker-Compose内置DNS负载均衡失效问题

Docker Compose实现负载均衡 还是对前面的例子docker-compose.yml稍微修改: version: "3.8"services:flask-demo:build:context: .dockerfile: Dockerfileimage: flask-demo:latestenvironment:- REDIS_HOSTredis-server- REDIS_PASS${REDIS_PASS}healt…...

[Python]Selenium-自动化测试

Selenium是一个web自动化测试的工具,在使用之前先在对应的项目添加工具包噢. 本文章主要简单的介绍了selenium对于自动化测试的使用 目录 添加浏览器驱动 get函数来到对应网站 驱动的定位 元素定位 id定位 class name定位 CSS定位 XPath定位 link text定位 定位一…...

高效管理文件夹名称:如何批量修改指定多样化的文件夹名称

在文件管理工作中,文件夹名称的管理对于整体的文件管理体系有着至关重要的作用。然而,往往我们会在文件夹名称的管理上遇到一些难题,如:需要修改的文件夹名称多样化,无法一次性满足所有需求。为了解决这个问题&#xf…...

c 读取音频协议WAV文件头(再生成wav文件)

查找wav文件头关键struct 位置,当然也可查找avi文件头。用这个方法找到avi文件data位置后,可直接读出文件的每一帧图片。当然avi数据的标志位不是data,可以是00dc等。 WAV音频头文件有三个关键struct:RIFF, fmt,data。 AVI 视频文件头的关键…...

Prompt设计与大语言模型微调

本文主要介绍了Prompt设计、大语言模型SFT和LLM在手机天猫AI导购助理项目应用。 ChatGPT基本原理 “会说话的AI”,“智能体” 简单概括成以下几个步骤: 预处理文本:ChatGPT的输入文本需要进行预处理。输入编码:ChatGPT将经过预处理…...

修复VS2015没有代码提示的问题【已解决】

问题描述 在Visual Studio 中编写代码时,发现使用库函数的时候,在类对象后输入点后,并没有出现类对应的成员信息的提示。 解决过程 1)方法1: 百度“vs 没有代码提示”,搜索解决方案。 方案1&#xff1…...

DeepSpeed: 大模型训练框架 | 京东云技术团队

背景: 目前,大模型的发展已经非常火热,关于大模型的训练、微调也是各个公司重点关注方向。但是大模型训练的痛点是模型参数过大,动辄上百亿,如果单靠单个GPU来完成训练基本不可能。所以需要多卡或者分布式训练来完成这…...

暄桐推荐|学书法的必读书目

在暄桐教室,写字之外,读书、静坐也是桐学们修习的功课。今天,便向你推荐,关于学习书法,暄桐教室的那些必读书目:    暄桐推荐学书法必读书之初阶书目:      对零基础的小白同学或刚入门…...

2023年赋能更多的人

最近接触到一些新人,是真正的网络新人,慢慢理解了新人的困惑。 对于新人,每天获取的信息五花八门,这是好的也是极其不好的。因为他们不知道如何筛选,到底适不适合自己去做。 我一直在劝大家去做一些内容创造性的事情…...

量子计算与量子密码(入门级)

量子计算与量子密码 写在最前面一些可能带来的有趣的知识和潜在的收获 1、Introduction导言四个特性不确定性(自由意志论)Indeterminism不确定性Uncertainty叠加原理(线性)superposition (linearity)纠缠entanglement 虚数的常见基本运算欧拉公式&#x…...

将安全作为首要目标 — Venus 的现状和前景展望

DeFi 的全面爆发将上一轮牛市推向巅峰。在不断的演化中,DeFi 领域也产生了很多新兴的细分领域,比如收益聚合器、合成资产、各种 DeFi 收益工具,以及最近整个市场都在讨论的 RWA 等。 DeFi 在不断进化,不变的是,DEX 和借…...

『第七章』翩翩起舞的雨燕:顺序与并发执行

在本篇博文中,您将学到如下内容: 1. 顺序执行2. 主线程 Main Thread 的秘密3. 并发执行:GCD 与分发队列(DispatchQueue)4. 延时执行5. 数据竞争(Data Race)6. 线程间的同步7. 避免线程爆炸8. RunLoop 与定时器总结楚客自相送,沾裳春水边。 晚来风信好,并发上江船。 花映…...

c语言进制的转换10进制转换16进制

c语言进制的转换10进制转换16进制 c语言的进制的转换 c语言进制的转换10进制转换16进制一、16进制的介绍二、10进制转换16进制的方法 一、16进制的介绍 十六进制: 十六进制逢十六进一,所有的数组是0到9和A到F组成,其中A代表10,B代…...

js中的Formdata数据结构

这里写目录标题 一、基本概念二、常用方法1.append(name, value)、set(name, value)2.get()、getAll()3.has(name)4.delete(name)5.keys(),values(),entries() 三、其他细节1.for of遍历2.转为对象3.结合 URLSearchParams 转为queryString 一、基本概念 FormData 提供了一种表…...