【Linux】进程的优先级及linux下进程的调度于切换

目录

​编辑

1.优先级是什么

2.linux中的优先级是怎么实现的

 ps -la 命令查看当前用户启动的进程​编辑

linux下调整优先级:

①先top一下

②点击r

③需要输入进程的pid

④回车 

​编辑 ⑤输入想将优秀级修改的值:

linux进程优先级范围为什么必须是【60,99】

linux为什么让优先级的调整是一种受限制的状态:

3.linux下进程的调度与切换

重点:并发---涉及到进程切换

理解进程切换:

linux实现进程调度的算法:linux2.6如何进行程序调度:

①queue【140】进程优先级数组

②bitmap[5] 位图--提升优先级的遍历效率 

③过期队列和活跃队列

④两个struct q * 的指针,实现活跃队列和过期队列的内容切换

 4.总结 进程的创建到调度


1.优先级是什么

我们日常生活中,要涉及确定优先级,一定是我们需要访问某种资源,食堂打饭排队,谁先打饭,

那么进程也是需要资源支撑的,

前提:进程要访问某种资源,进程进行一定的方式(排队),确定享受资源的先后顺序。

优先级和权限的区别

本质区别是:权限觉得能不能,优先级决定先后,只要到了优先级这一层那么说明权限几乎已经具备。

为什么要存在优先级

本质原因:资源过少

而资源的多少是一个相对的概念,相对于需求资源的人的数量。为什么需要运行队列,cpu只有一个

2.linux中的优先级是怎么实现的

编写代码如下:

 ps -la 命令查看当前用户启动的进程

PRI就是优先级

task_struct{
//优先级int PRI}

就是计算机里面的整数,,相当于排队给你一个号码

linux默认优先级从80开始

linux优先级可以在启动前后中被修改

linux优先级的范围:【60,99】 40个数字

linux优先级本质是一个数字,数字越小,优先级越高

linux下调整优先级:

(实际中没有需要我们调整优先级的环境或者情况)

top命令

top命令经常用来监控linux的系统状况,是常用的性能分析工具,能够实时显示系统中各个进程的资源占用情况。

①先top一下

②点击r

③需要输入进程的pid

④回车 

 ⑤输入想将优秀级修改的值:

我们这里测试输入10回车

PRI变为90了,NI变为10

linux中允许 用户调整优先级,但是不能直接让你修改pri,而是在linux中存在一个nice值的概念,是修改nice值。这个nice不是优先级,而是进程优先级的修正数据。

真正的优先级 = 老的优先级(priold)+nice值(这就是内核确认优先级的方式)

linux进程优先级范围为什么必须是【60,99】

我们做一个极端值测试

刚才的进程优先级被调成90了

我们现在top

r一下

设置过于频繁不让设置

 sudo top

在执行r就行

此时 :

说明我们的nice值是被覆盖写入的,刚才是10,现在是-10 ,可是pri变成90,不应该老的优先级+nice = 80吗

我们看下面的prI 为80,NI为0,如果我们真的变成80 -10 数据就不一致了,

老的pRI都是80开始,

我们将优先级设置100,

说明我们的linux内核会做判断, 如果nice调整过大,只会取nice极值,极大值为19.

 nice值取值范围【-20,19】,所以优先级的取值范围为【60,99】

linux为什么让优先级的调整是一种受限制的状态:

如果不加限制,很多的程序员工程师就可以将自己进程的优先级调整非常小,别人的调整的非常大,系统中还有些正常进程。优先级决定了进程享受资源的前后,如果进程的优先级很小,调度器cpu在短时间内较大概率会频繁的调度这个进程,导致调度不太平衡,导致优先级高的优先得到资源,后续还有源源不断的进程产生,最后会导致常规进程很难得到cpu资源,意味着这个进程很长时间不被调度,作为一个要运行的进程,变得很卡顿,而其他优先级高的进程很快就跑完了,所以,这种情况称之为“进程饥饿”,就像去打饭长由于被插队长时间打不到饭。我们任何的现在的分时操作系统,按照时间段进程运行,每个进程运行一个时间段,在调度上都要进行公平的调度,否则会导致饥饿问题。所以进程优先级调整必须受限制。

3.linux下进程的调度与切换

概念准备

①进程在运行的时候,放在cpu上,cpu必须将进程代码执行完,才可以吗?

不对,死循环本身就不会执行完,现代操作系统,都是基于时间片进行轮转执行。

时间片:给每一个进程规定一个运行的最大时间。跑完一个时间片,操作系统将整个进程从cpu剥离,由调度器帮助完成。

进程和进程之间一定存在竞争,从优先级就可以看出来,本质cpu资源少,进程数目多,但是不能让大家恶意竞争,所以得有调度器基于时间片和优先级轮转调度。

进程之间是具有独立性的:

关掉任何一个进程对其他进程的运行都不影响(不影响别的进程的执行,代码和数据是安全的)。进程在运行期间,逻辑上我们认为其独享资源,多进程运行期间互不干扰。

如果电脑里面有两个cpu,在任意一个时刻,可以允许两个进程被同时调度执行,这叫两个进程并行运行。(多核cpu:所谓多核,一块cpu里面有一个控制器和很多运算器,可以跑很多计算,但是这些计算都是一个进程中的多条代码),如果计算机一个cpu,每个cpu都有其时间片,假设这个时间片为1毫秒,我们此时有十个进程,那么1秒里面就有1000个时间片,也就是意味着每个进程会被调度100次,微观上是卡顿的,但是人类感知不到,所以我们就感觉一个时间段内多个任务在跑,一个时间段内,多个代码可以推进叫做并发,是指进程在一个cpu下才有进程频繁切换的动作。一段时间内进行频繁的进程切换,就像当年葫芦娃的动画片是一张一张画出来,加速翻动。

竞争性: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高 效完成任务,更合理竞争相关资源,便具有了优先级

独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰

并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行

并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为 并发

重点:并发---涉及到进程切换

cpu中存在大量寄存器:eax,ebx,ecx,edx,eds/ecs/fg/gs/eip/cro,crocr4 程序状态字,浮点数寄存器

ebp.esp(寄存器保存大量的临时数据)

eip俗称pc指针,程序记步器。

程序状态字:除0,异常退出

不同寄存器有不同的功能:比如eax用于保存临时数据

进程在cpu上运行,cpu上的所有寄存器要围绕这个进程进行展开运算运行,所以进程在运行的过程中,会产生大量的临时数据,放在cpu的寄存器。这些临时数据存在的意义支撑了当前进程运行到了什么状态,运行到了哪一步,不属于寄存器的数据都属于进程独有的数据。

理解进程切换:

所有的保存都是为了恢复,所有的恢复都是为了继续上次的运行位置继续运行。

当前进程的信息都在寄存器保存,如果进程运行时间片到了,进程切换时,将临时数据带走,

cpu内部所有的临时数据,我们叫做进程的硬件上下文数据,所以当进程走的时候,要将这些临时信息保存下来,保存在pcb字段,这个动作叫做保护上下文,此时这个进程已经算是从cpu上剥离了。首次调度,数据覆盖,第二次调度数据恢复:进程被放到cpu上开始运行,将曾经保存的硬件上下文数据进行恢复,

、两个工作:保护山下文,上下文恢复

switch_to
->__switch_to... //浮点寄存器等的切换->cpu_switch_to(prev, next)
arch/arm64/kernel/entry.S:
1032 /*
1033  * Register switch for AArch64. The callee-saved registers need to be saved
1034  * and restored. On entry:
1035  *   x0 = previous task_struct (must be preserved across the switch)
1036  *   x1 = next task_struct
1037  * Previous and next are guaranteed not to be the same.
1038  *
1039  */
1040 ENTRY(cpu_switch_to)
1041         mov     x10, #THREAD_CPU_CONTEXT
1042         add     x8, x0, x10
1043         mov     x9, sp
1044         stp     x19, x20, [x8], #16             // store callee-saved registers
1045         stp     x21, x22, [x8], #16
1046         stp     x23, x24, [x8], #16
1047         stp     x25, x26, [x8], #16
1048         stp     x27, x28, [x8], #16
1049         stp     x29, x9, [x8], #16
1050         str     lr, [x8]
1051         add     x8, x1, x10
1052         ldp     x19, x20, [x8], #16             // restore callee-saved registers
1053         ldp     x21, x22, [x8], #16
1054         ldp     x23, x24, [x8], #16
1055         ldp     x25, x26, [x8], #16
1056         ldp     x27, x28, [x8], #16
1057         ldp     x29, x9, [x8], #16
1058         ldr     lr, [x8]
1059         mov     sp, x9
1060         msr     sp_el0, x1
1061         ret
1062 ENDPROC(cpu_switch_to)

cpu有多个寄存器,但是只有一套,寄存器内部保存的数据可以有多套。

区分:寄存器vs寄存器的内容

铁打的寄存器,流水的数据。虽然寄存器数据放在了一个共享的cpu设备里面,但是所有的数据起其实都是进程私有的。进程在剥离的时候会将临时数据拿走。也就是cpu内的数据在任意时刻属于一个进程,大家去读书馆看同一本书,自己看到那一页这样的数据只属于你,大家都坐在一个位置读书,读一本书,但是属于自己的还是只会属于自己。

 进程在cpu上的一生:

首先执行:生成硬件上下文,执行时间片,保存上下文投递到pcb,等待,再次被调用在恢复上下文,所有进程按照这样一样的套路然后被cpu轮流调度,而相关的内容和数据都在内存里,所以访问的速度会非常快,所以进程之间进行轮转的速度也不慢。是按照基于时间片的fifo算法运行。

linux实现进程调度的算法:linux2.6如何进行程序调度:

要考虑优先级和饥饿问题,更重要的linux具体的进程调度要考虑效率

一个cpu对应的运行队列:

①queue【140】进程优先级数组

queue 是一个task_struct * 的指针数组,未来指向一个一个的进程,数组大小为140,0-99是不用的,只采用:100-139,linux不仅仅要考虑基于公平的进程调度这样的原则对应的操作系统 是一种实时操作系统,与分时操作系统相对的:

实时操作系统:(作为软件开发大概率用不到),我们现在的操作系统调度的时候都是相对公平的,保证进程在相同的时间片内享受同等的资源,即使有优先级,差距也不会很明显,但是有一类操作系统叫实时操作系统:一但进程运行起来了,就必须将当前进程跑完,然后再跑下一个,所有的进程都必须严格按照顺序去进行依次执行,如果有更高优先级的进行,先调度,实时操作系统对用户有高响应,用户的动作来了,操作系统就必须立马执行。这种叫做实时操作系统。这种操作系统适合于我们现在的自动驾驶,我用户要刹车了,操作系统不能说进程要排队,先把QQ音乐运行完。所以学习操作系统很多东西是在不同情况下使用的,所以,我们当前操作系统只考虑我们的100-139,0-99表示的实时优先级。

进程被调度后,然后通过优先级:优先级-60+100放入数组的对应下标的优先级队列中:

比如优先级为80,80-60+100 = 120,放入下标为120的进程中 

进程进入队列不是胡乱进入的,而是结合自己的优先级进入,每个进程根据自己的优先级进行排队,优先级队列,操作系统只用对优先级数组通过下标遍历,实际操作系统没有那么多的进程, 

②bitmap[5] 位图--提升优先级的遍历效率 

但是我们这里毕竟还是40个队列,难道每次都要变量整个数组检测吗?虽然是常数级,而且判断也只不过是为空不为,但是还是比较麻烦,linux给我们提供了一个bitmap[5]这个变量,是一个int 类型变量,一个整型4个字节,32个比特位,32*5 = 160,160个比特位,用比特位的位置,表示哪一个位置,比特位的内容表示该队列是否为空:其中有20个比特位不用:

 比特位为1说明有进程队列,如果为0就说明没有进程队列,所以检测队列中是否有进程就转换为检测对应的比特位是否是1.位操作比遍历操作快得多。我们当时检测比特位为1的数目这样的题目是做过的,以整型为单位,一次可以检测32个队列,如果bitmap某一个下标(0-4),位0,说明这32个进程队列为空,数字不等于0,说明有1,那么我们找到最小比特位为1的进程队列就可以,效率大大提升。在选择进程这件事上时间复杂度几乎可以做到O(1),不管有多少进程,对于操作系统来说只是检测位图的事情,所以这也被称之为:O(1)调度算法

但是到现在进程的调度还是有一些疑问:如果我们现在的进程很多都是优先级高的进程,是不是就意味着优先级低的进程的饥饿went还有实际上进程在运行的时候,操作系统还要放入进程,那么会不会导致一个进程优先级的进程队列一直在运行,其他优先级的就是饥饿状态,是存在的。但是我们的设计者非常聪明:又搞了一块一模一样的结构:

③过期队列和活跃队列

当我们cpu在进行正常执行的时候,选中一个数组,调度上面所有进程,后续再来的进程就到下一个优先级数组里面去。当前运行的数组优先级队列叫做活跃队列,而后续我们进程放入的队列称为我们的过期队列。cpu调度cpu的,操作系统放操做系统的进程,相当于一期一时期的调用,过期队列的位图相应的也设置好。

④两个struct q * 的指针,实现活跃队列和过期队列的内容切换

对于设计者来说:

这两个东西存放的数据和数据类型是一样的呀,就可以使用一个数组来管理这两块,那么这个数组的类型应该是一个结构体的类型:

struct q{
nr_active;//当前队列中有多少活跃的进程,也就是进程优先级最高的进程bitmap[5];//进程的位图queue[140];//进程队列数组}

那么我们创建这样一个数组:struct q arr[2];

arr[0]就代表我们的活跃队列

arr[1]代表过期队列

然后我们的运行队列中还有两个struct q * 的指针:

struct q* active = & arr[0]      struct q* expired = &arr[1]

分别对应我们的活跃队列和过期队列,后续我们的操作体系调度时都是通过指针读取bitmap和优先级数组,然后就就可以访问进程了。

而对于新增进程,都放入过期队列中,活跃队列进程不断减少运行完毕,过期队列进程不断增多,然后我们将两个指针指向的内容进行交换,我们的过期队列里面的内容就变成活跃队列内容了,周而复始,基于优先级队列的O(1)的调度算法调度进程就可以完成了。

两个指针交换的时候,更改的是指针变量的内容也就是地址交换呀,只有4字节或者8字节的数据交换。

这样的设计:

每一次调度都是o(1)时间复杂度,每个优先级都可以照顾到位,对应40个优先级的数组

第二个,调度效率高,通过位图确定特定优先级

第三个还考虑了饥饿的问题,因为经过过期和活跃队列切换,让优先级低的进程也能被调度。

 4.总结 进程的创建到调度

进程创建后接着创建进程的 pcb,将数据和代码加载到内存,进程pcb排入进程队列,同时pcb还要属于所有进程都在的双链表中,一但被调度,就要看进程的状态和优先级,状态:可能在运行可能在阻塞,状态决定了进程状态字段是多少(0,1,2表示t,s等),以及pcb进入哪一个等待队列,有了优先级就可以正常执行了,根据优先级执行一定要先保证能够实现基本的进程的切换,因为要被调度,可能一个时间片没有跑完,就要执行上下文的切换,就有上下文保护和恢复的概念,我们的切换就有了,我们的进程被动态执行调度就有了,然后再看系统层面上如何对进程做调度做管理,linux内核采用的是基于大O(1)的时间片轮转算法:两个队列再用两个指针,必要时进行交换。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

自编译支持CUDA硬解的OPENCV和FFMPEG

1 整体思路 查阅opencv的官方文档,可看到有个cudacodec扩展,用他可方便的进行编解码。唯一麻烦的是需要自行编译opencv。 同时,为了考虑后续方便,顺手编译了FFMPEG,并将其与OPENCV绑定。 在之前的博文“鲲鹏主机昇腾A…

osg场景图的数据结构

1、Scene Graph场景图 场景图是一种描述三维场景的数据结构:它是一个有向无循环图。 OSG中不仅定义了场景图的数据结构,还提供了对这种图数据结构的各种访问方式,或者说是管理方法,如渲染。 2、常见节点 备注:Tranform变换的是模…

小车项目介绍

STM32智能小车基于STM32F103C8T6进行开发 该项目具有OLED,USART串口,ADC测量电压,陀螺仪,超声波测距模块,红外循迹模块,蓝牙模块,按键,电机驱动,电机,舵机,电源等功能 功能详细介绍: OLED模块 使用:OLED显示屏模块 0.96寸 IIC/SPI 选择原因:价格较低、使用方便…

如何在jmeter中把响应中的数据提取出来并引用

jmeter做接口测试过程中,经常遇到请求需要用到token的时候,我们可以把返回token的接口用后置处理器提取出来,但是在这种情况下,只能适用于当前的线程组,其他线程组无法引用到提取的token变量值,所以必须要生…

如何用好PMP项目管理知识

PMP(Project Management Professional,项目管理专业人士)是由国际项目管理协会(PMI)颁发的全球最高级别的项目管理认证,认证需要通过严格的考试,并具备相应的工作经验和教育背景。 作为一名咨询师,我们经常…

vscode和pycharm等idea编写protobuf文件格式化

想在pycharm或者goland等idea中开发protobuf文件的话,可以安装一个插件:protocol-buffers 安装之后,proto文件就会支持高亮和格式化了。 如果是vscode想要编写proto文件,可以安装另外一个插件:vscode-proto3 安装后&a…

C++修炼之路之list模拟实现--C++中的双向循环链表

目录 引言 一:STL源代码中关于list的成员变量的介绍 二:模拟实现list 1.基本结构 2.普通迭代器 const迭代器的结合 3.构造拷贝构造析构赋值重载 清空 4.inserterase头尾插入删除 5.打印不同数据类型的数据《使用模板加容器来完成》 三&#xf…

AGI趋势/创业的从业者

红杉这两年分享了好多AI文章,收录了多篇关于GenAI的观点和文章,涉及GenAI的未来、趋势、应用和挑战等话题。 比如: 2024 年的人工智能:从大爆炸到原始汤 下一个十亿开发者 生成式人工智能的第二幕 AI 的 $200B 问题 将生成式…

2024 MathorCupC题完整解题及成品论文!

C 题 物流网络分拣中心货量预测及人员排班 电商物流网络在订单履约中由多个环节组成,图 1 是一个简化的物流 网络示意图。其中,分拣中心作为网络的中间环节,需要将包裹按照不同 流向进行分拣并发往下一个场地,最终使包裹到达消费者手中。分拣中心 管理效率的提升,对整体网络的…

华为ensp中nat server 公网访问内网服务器

作者主页:点击! ENSP专栏:点击! 创作时间:2024年4月15日17点30分 NAT服务器是一种在网络边界设备上配置的服务,它允许外部网络的用户访问内部网络中的服务或主机,同时隐藏了内部网络的真实IP地…

快速探索随机树-RRT

文章目录 简介原理算法运动规划的变体和改进简介 快速探索随机树(RRT)是一种算法,旨在通过随机构建空间填充树来有效搜索非凸高维空间。该树是从搜索空间随机抽取的样本中逐步构建的,并且本质上偏向于向问题的大型未搜索区域生长。RRT 由 Steven M. LaValle 和 James J. K…

冯喜运:4.16市场洞察:中东风暴搅动汇市,现货黄金原油走势分析

【黄金消息面分析 】周一(4月15日),欧洲时段黄金价格已经从高点回落,目前交投于2351.52美元/盎司,稍早曾短暂攀至2372美元,未能重现上周收盘时触及的2431美元高位。定于周一晚些时候公布的美国3月零售销售数据也可能对美元汇率产生…

PgSQL之WITH Queries/Statement

PostgreSQL WITH 子句 在 PostgreSQL 中,WITH 子句提供了一种编写辅助语句的方法,以便在更大的查询中使用。 WITH 子句有助于将复杂的大型查询分解为更简单的表单,便于阅读。这些语句通常称为通用表表达式(Common Table Express…

1260. 二维网格迁移

1260. 二维网格迁移 原题链接:完成情况:解题思路:参考代码:错误经验吸取 原题链接: 1260. 二维网格迁移 https://leetcode.cn/problems/shift-2d-grid/description/ 完成情况: 解题思路: 这…

【yolov5小技巧(2)】---将yolov5中的特征图以热力图的方式进行可视化

文章目录 🚀🚀🚀前言一、1️⃣ 将特征图可视化的文章CFPNet二、2️⃣yolov5自带的特征图可视化工具三、3️⃣如何将特征图转换成热力图 👀🎉📜系列文章目录 【yolov5小技巧(1)】—可视化并统计目标检测中的…

IDEA 设置类注释模板作者、日期、描述等信息(推荐标准!)

idea注释模版配置 idea作为越来越多程序员使用的开发工具,平时的代码注释也非常的关键,类上注释和方法上注释每次换电脑或者新同事入职都要统一修改,找了网上好多教程都写的乱七八糟的啥都有,为方便统一就自己写一个操作方法&…

Redis入门到通关之ZSet命令

文章目录 ⛄概述⛄常见命令有⛄RedisTemplate API❄️❄️ 向集合中插入元素,并设置分数❄️❄️向集合中插入多个元素,并设置分数❄️❄️按照排名先后(从小到大)打印指定区间内的元素, -1为打印全部❄️❄️获得指定元素的分数❄️❄️返回集合内的成员个数❄️❄…

网络安全-自学笔记

一、自学网络安全学习的误区和陷阱 1.不要试图先成为一名程序员(以编程为基础的学习)再开始学习 我在之前的回答中,我都一再强调不要以编程为基础再开始学习网络安全,一般来说,学习编程不但学习周期长,而…

Springboot+Vue项目-基于Java+MySQL的免税商品优选购物商城系统(附源码+演示视频+LW)

大家好!我是程序猿老A,感谢您阅读本文,欢迎一键三连哦。 💞当前专栏:Java毕业设计 精彩专栏推荐👇🏻👇🏻👇🏻 🎀 Python毕业设计 &…

PCIe错误定义与分类

前言: PCI总线中定义两个边带信号(PERR#和SERR#)来处理总线错误。其中PERR#主要对应的是普通数据奇偶校检错误(Parity Error),而SERR#主要对应的是系统错误(System Error)。具体如下…