ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Linux进程(四).进程优先级以及进程切换,进程调度

Linux进程(四).进程优先级以及进程切换,进程调度 一.进程优先级1.是什么进程优先级是得到CPU资源的先后顺序。那么优先级和权限有何区别呢优先级是能够得到CPU资源只是先后问题而已而权限考虑的是能否得到资源的问题。2.为什么要设计优先级原因在于CPU资源有限要通过优先级去确定谁先谁后。3.怎么办进程优先级是task_struct里的一个属性是一个int数字。值越低优先级越高。①.知识点补充——uiduid:即user idOS识别用户是谁的东西每个用户都有一个唯一的uid这就是进程为什么访问文件的时候OS准确识别出访问者是owner还是other还是所属组。来说说是怎么识别的当查询某个进程的相关信息时也会显示当前用户的uid即显示派自己来做事的老大是谁:创建文件时文件也会储存三个角色的uid:而访问文件的指令本身就是进程那么指令这个进程也会存有uid通过比对文件的uid和指令的uid如果和文件哪一个角色的uid相等那么就判定访问者是什么角色。用户-bash(OS给每个用户一个bash)-将访问任务交给多个进程(指令)-每个进程完成自己的访问任务。因而进程就代表用户就像杨金水代表朝廷管理江南织造局一样。此处补充父父子子部分知识点不够此后再做讲解的部分②.回归正题在进程详细信息这个列表中PRI就代表进程的优先级它的默认值是80这个值可以改变但不建议改动。而NI是nice值代表进程优先级的修正数据通过更改NI就可以更改优先级。得出一个结论这里有个坑每次调整优先级都是从默认值开始去加NI值所以千万不要拿PRI那列的数字去加NI值。同时NI值是有范围的[-20,19]LinuxPRI默认值为80所以实际优先级的范围是[60,99]为什么要去设置一个范围呢原因是为了进程得到CPU资源的公平性得让每个进程不能等的太久。长期得不到资源的进程会有进程饥饿的现象出现。就像排队在食堂打饭等太久人都饿麻了。二.切换进程1.知识点补充——竞争独立并行并发①.竞争OS内的进程数量始终是要多余CPU的资源的所以进程间必然发生竞争。为了高效完成任务合理竞争资源就有了进程优先级。②.独立就像任务管理器里有很多进程在使用CPU资源将其中一个进程结束并不会影响其他进行的运行。每个进程在使用资源期间这些资源供其独享多个进程之间互不干扰。至于如何做到独立性我们后面的文章的谈到。③.并行与并发并发一个CPU先服务一个进程然后迅速断开再服务另一个。并行多个CPU同时服务多个进程。2.进程切换①.死循环如何运行每个进程都会被分配到一个叫时间片的东西这是个时间段当CPU服务这个进程的时间超过时间片就会停止服务换句话说进程拥有CPU资源不是永久拥有的而是在时间片这段时间内暂时被拥有时间一到CPU就会切换另一个进程进行服务。所以进程拥有太多的数据或代码的话是不一定能在一次服务里被执行完的。而死循环进程并不会一直执行下去直到内存被消耗完卡死系统当其运行时间超过时间片CPU就会切换服务的进程。②.浅谈CPU的寄存器1.CPU内部存在多个寄存器多个寄存器临时储存一个正在运行的进程的上下文数据。2.寄存器寄存器里的内容。寄存器就是运输机本身只有一份寄存器里存的临时数据就是装在运输机里的东西要么是坦克士兵大炮要么混着来反正不唯一也不重样运载的武器换了但运输机还是它自己。③.如何切换进程Ⅰ.与大学生参军入伍的例子类比出切换的过程进行一次保留剥离再恢复的过程就是进行一次切换进程。Ⅱ.具体切换的过程数据经拷贝以后存储在何处如何区分全新进程和已经调度过的进程呢三.Linux进程调度切换和调度共同构成了调度器。我们在上一篇文章梳理了调度队列如何处理阻塞的原理但那是关于操作系统学科范畴属于纸面的东西这一部分将要从Linux底层的角度去了解调度。1.前备知识在了解整个底层之前得明白我们正在使用的操作系统是分时操作系统是基于时间片进行调度的而不是当下谁重要谁优先级就最高的实时操作系统。但Linux操作系统是具有一定的实时操作系统功能的只是平时使用时被裁掉或被关闭了而已。2.映射算法queue[140]数组里有140个位置每个位置都存储一个task_struct指针前100个属于实时优先级不考虑剩余40个就刚好对应了分时优先级[-20.19]里的40个优先级NI值的范围。那么如何将分时优先级映射到剩余40个位置里储存起来呢这40个位置的首个位置下标是10060是默认值80 优先级最小NI值-20用60作为被减数的原因是求一个偏移量即当前优先级到最小优先级的偏移量后面的100是最小优先级的下标值因而用加上偏移量就可以求当下进程的优先级的下标映射算法:这般映射出的是queue的下标3.调度规则既然能玩映射那么这个queue[140]的本质是一个哈希表。假如几个进程的优先级相同那么就可以像哈希桶那样将这几个进程全部链接在那个位置上。那么就可以总结一下在整个宏观的queue上看优先级按照进程优先级(也就是顺着queue往下)来进行调度但需要逐个节点的去遍历可能会出现遍历到的节点没有进程的情况找到第⼀个⾮空队列该队列必定为优先级最⾼的队列。在局部的同一个位置即优先级相同时按照先进先出的原则对链表上的进程进程调度。所以就要分两步先挑队列再挑进程。4.调度器如何快速调度按照以上的调度方式调度器去寻找某个进程在链表上的开销是O(1)在整个队列上的开销是O(N)那么总开销就是O(N)是比较低的那么调度器可否快速挑选进程呢造成低效率的原因是挑队列的时候我无法知道哪个位置是有task_strucrt的因此需要在队列上从上往下按着优先级来逐个遍历队列元素。这就不得不提runqueue里位于queue[140]上方的bitmap[5]了这是个无符号整型的map一个无符号整型的数是32位那么5个就是160位每位与runqueue上的元素一一对应每个比特位无非两种结果——0或11就代表queue对应的元素存在task_struct,反之就不存在。所以挑队列时就可以根据map筛出有task_struct的位置然后在这些位置中再挑进程。就能在O(1)的开销下挑队列。那为啥是160个比特位也就是5个无符号整型呢原因是4个数128位没法覆盖包揽runqueue每个节点,6个数192位又过于浪费了。那么闲置的20个就不用了。5.切换与调度的整个流程以及解决进程饥饿的方式①.切换与调度nr_active代表整个队列一共有几个进程。调度的时候先查看nr_active是否为0如果不为0就往下去map[5]里查询不为0的queue元素当调度器拿到不为0的元素以后就到queue里这几个元素从上到下去找处于最上端的元素然后该元素的链表里链表头的节点就是优先级最高的进程这时就把该进程拿到CPU去切换超过时间片的进程至于如何切换就看上面切换的部分。当这个进程运行时间超过时间片后被切换下去如果它回到原来那个元素的链表的队列尾部。但这会出一个大问题就是按照这么来调度调度器始终就在优先级高值小的元素链条上反复执行调度而queue下面优先级小值大的非零元素连口汤都喝不到就造成了进程饥饿。②.解决进程饥饿为了解决这个进程饥饿的问题runqueue又在其内部搞了个过期进程它也有map[5]nr_activequeue[140]这一套三个成员。没有调度过的进程进上面活跃进程的queue[140]里被切换下来调度过的进程进下面过期进程的queue[140]里。然后活跃队列会越来约少过期队列会越来越多。那么系统是如何方便管理和调用过期进程和活跃进程的成员的呢过期进程和活跃进程的三个成员变量都分别被装在两个结构体rqueue_elm里然后再定义一个数组:用来装过期进程和活跃进程的结构体其中arry[0]就是活跃进程arry[1]就是过期进程。随后再在runqueue中定义两个指针*active和*expired让*active指向array[0]即指向活跃进程。*expired指向array[1]即过期进程当活跃进程的queue里的进程完全被调度完毕均被放进过期进程之后会交换active和expired指针的内容让被切换过的进程重新被调度执行直至进程完全被执行完毕
返回列表