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

Linux——进程调度与切换

一、进程优先级

        进程的优先级指的是进程得到CPU资源的先后顺序。因为在冯诺依曼计算机体系中,CPU的资源是紧缺的,我们需要把有限的资源分配给非常多的进程,如果进程之前没有优先级的区别,那么当有一些进程需要提前运行的时候,它可能会就会被其他的进程堵在后面,导致需要处理完这个进程以后才能处理的其他东西就会停滞,这个时候CPU的效率就降低了。所以每个进程都要有自己的优先级。

        我们都知道一个进程是系统内核数据结构 + 代码数据,那么优先级其实也是通过系统内核数据结构来管理的,在Linux操作系统下 ,进程的优先级就是task_struct中的一个int类型的成员变量,我们也可以通过ps命令查看一个程序的优先级。

        其中一个进程的优先级由两部分组成,一个是PRI,另外一个是NI值,PRI表示的是进程的优先级,默认值是80,而NI表示的是进程优先级的修正数据。一个进程的真实优先级 = PRI(默认值) + NI值。

        调整进程优先级的方式

        我们可以进入top,然后按r,输入进程的PID,然后再输入NI值,这样就能改变进程的优先级。

        但是我们再用这个方法去更改一次NI值时,我们会发现系统就不让我们更改了,这里可以看出,系统是不允许我们频繁的修改进程的优先级的。

        我们还可以通过nice -n [NI值] [你的命令],这样可以设置你的这条命令在运行的时候的优先级。

        还可以通过renice -n [NI值] -p [进程PID],调整一个进程的NI值。

        从这里我们也可以看到调整优先级是通过调整NI值来实现的,我们的命令都是修改NI值,同时每次修改PRI都是在PRI的默认值加上NI值。

        优先级的极值

        这里我们把一个进程的NI值设的特别大,或者把NI值调的特别小的时候,我们会发现,在实际调整时,只会被调整成19或者-20,这就可以得出一个结论,我们的PRI值是有范围的,它的范围是[60,99]。

二、进程切换

        当代的计算机操作系统基本上都是基于时间片的分时操作系统,在这种操作系统下进程的运行并不是一次性就会完成的,系统会给进程一个时间,当前进程在这段时间内运行,运行到哪就到哪,当时间一到,当前进程就会被下一个进程顶替,然后下一个进程继续和之前一样的操作,所以当我们的程序中有一个死循环的时候,我们的操作系统并不会因此就卡死,我们同样能进行其他的操作。

        这里我们还可以了解一下进程的几个特性:竞争性独立性并行并发

        竞争性:在一个系统中进程的数量是众多的,但是CPU资源的数量是有限的甚至可以说是有限的,所以各个进程之间都在竞争CPU资源,所以进程之间是具有竞争属性的。在操作系统中为了更高效的完成任务,更合理的竞争相关的资源,所以有了进程的优先级。

        独立性:多个进程在运行的时候,他们需要的资源是独享的,也就是说多个进程在运行期间是互不干扰的。

        并行:多个进程在多个CPU下分别同时运行,这种状态叫做并行。

        并发:多个进程在一个CPU下采用进程切换的方式运行,也就是在一段时间内,让多个进程都运行一段时间,这种被称为并发。

        寄存器

        在CPU的内部有很多的寄存器,而里存储的数据就是正在运行的进程中的一些临时数据,也就是说寄存器就只是CPU内部的临时空间,换个方式说,也就是 寄存器 != 寄存器里面的数据。当CPU运行某个进程的时候,CPU会把该进程运行的上下文数据加载到寄存器中,当分给这个进程的运行时间结束时,CPU又会把当前寄存器里的数据存起来,当下次恢复进程的时候再把这些数据恢复到CPU的寄存器里去。

        在CPU中,寄存器只有一份,但是上下文数据可以有很多份,分别对应不同的进程,当进程暂时被从CPU上切下来时,进程走的时候就需要保存并带走自己的上下文数据,把这些数据保存到task_struct里面,这样做的目的就是为了下次再回来的时候,能够按照之前的逻辑继续运行。所以说进程切换中最核心的过程就是保存和恢复当前进程的硬件上下文数据,即CPU寄存器内的内容

        Linux的进程调度算法

        一个CPU都会有一个运行队列,这个运行队列中有很多的成员,首先我们要关注的是里面会有一个大小为140的queue,这个queue是一个指针数组,每个存储的类型是task_struct,也就是说我们的进程根据优先级,按照FIFO的规则进入这个数组,这个数组中的每一个成员都是一个队列。而这个数组中的[0,99]被称为实时优先级,我们不考虑;[100,139]是我们会用到的,根据一个进程的优先级,它会被链入对应的位置计算的方式为 x - 60 + (140 -40),这里其实也就对应了为什么我们在调整一个进程的NI值时它的范围是[-20,19]。

        如果只有这个queue的话,那系统在运行的时候还需要检查某个位置是否有需要运行的进程,效率就会很低,所以又添加了一个bitmap[5]的位图,32 * 5 = 160个位置,只要检查位图中的这个位是1还是0,然后是1就说明对应的优先级里有需要运行的进程,为0则没有。

        这样其实只解决了优先级和查找的问题,当一个进程运行完它的时间片时,如果又把它插入到当前队列的尾部的话,那这样是无法让每个进程都运行一段时间的,这样只会把优先级高的进程全都运行完了以后才会再运行优先级较低的进程,还是非常容易造成进程饥饿。所以在runqueue会有两套一模一样的queue和bitmap,一套叫做活跃队列,一套叫做过期队列,同时runqueue中还有两个指针active和expired;active永远指向活跃队列,expired永远指向过期队列。

        当一个进程执行完了以后,它会从活跃队列中被删除,同时被插入到过期队列中相应的位置,这样每个进程都能按照优先级的顺序被执行,同时每个进程在一段时间内都能被推进一段时间。当活跃进程里的进程都被运行过了以后,queue为空时,交换active和expired指针指向的内容,这样活跃队列和过期队列里的信息又进行了交换,下一轮执行的时候,又能继续按照之前的顺序运行进程了。这样的算法被我们称为进程调度O(1)算法


http://www.kler.cn/a/410533.html

相关文章:

  • 国土安全部发布关键基础设施安全人工智能框架
  • 速盾:CDN缓存的工作原理是什么?
  • Linux麦克风录音实战
  • 5. Autogen官网教程 (Tool Use)
  • windows server 2019 启动 nginx 报错
  • 【Spiffo】环境配置:VScode+Windows开发环境
  • 风尚云网前端学习:一个简易前端新手友好的HTML5页面布局与样式设计
  • 《Docker Registry(镜像仓库)详解》
  • vue实现列表滑动下拉加载数据
  • sql server 主从job对比差异
  • python画图|无坐标轴自由划线操作fig.add_artist(lines.Line2D()函数
  • 英伟达推出了全新的小型语言模型家族——Hymba 1.5B
  • 【开发小技巧11】用经典报表实现badge list效果,根据回显内容用颜色加以区分
  • 【SQL Server】华中农业大学空间数据库实验报告 实验八 存储过程
  • MySQL的权限管理机制--授权表
  • 卷积神经网络学习记录
  • linux上的性能观测工具
  • Redis密码设置与访问限制(网络安全)
  • 每日一书 《基于ArcGIS的Python编程秘笈》
  • C#winform:连接mysql,并将数据展示到页面
  • 数据库-MySQL-Mybatis源码解析-设计模式角度
  • Redis 过期策略和内存淘汰策略
  • Flutter封装Coap
  • 道品科技移动式水肥一体机:智能园艺的新选择
  • 【Python】构建事件驱动架构:用Python实现实时应用的高效系统
  • CPU性能优化--微操作