尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Linux:进程的优先级和进程是怎么组织的

Linux:进程的优先级和进程是怎么组织的 一、前言前面文章已经能让我们对进程的静态层面有点理解,接下来下面学的进程的属性能让我们把进程在我们脑子里动起来!!!二、进程的优先级2.1优先级的概念• cpu资源分配的先后顺序就是指进程的优先权priority。• 优先权⾼的进程有优先执⾏权利。配置进程优先权对多任务环境的linux很有⽤可以改善系统性能。优先级VS权限我们知道权限的作用是:你能不能做某件事情或获取某资源。 而进程优先级是在能做或获取前提下的先后问题为什么要有优先级呢?-因为资源是有限的,就比如你在食堂打饭,为什么不每一个人建一个窗口,这样就不用排队了? 资源不足嘛所以只能弄几个窗口排队打饭嘛,这里也是一样,CPU只有一个(普遍的计算机),你每个人都要与我交互如果没有秩序就会乱套2.2查看进程ps -l 就能查看下面的内容• UID:代表执⾏者的⾝份• PID:代表这个进程的代号• PPID代表这个进程是由哪个进程发展衍⽣⽽来的亦即⽗进程的代号• PRI代表这个进程可被执⾏的优先级其值越⼩越早被执⾏• NI代表这个进程的nice值PID和PPID我们上篇文章讲了不在多说,UID就是比如你是root用户你的创建的文件所属组和拥有者会是root,但root也有它的代号,就是root代号可以通过命令改(ai可以搜搜~~)PRI和NI我们创造的进程的优先级默认是80,想修改优先级的话就修改NI的值就能更改优先级,PRI(new)PRI(old)NI(nice),但是这里的PRI(old)是默认的80NI值怎么改,Ni的范围是什么?我们可以这样修改首先输入top命令查看优先级然后输入r来输入进程的PID,然后再填写你要的NI值最后输入q退出但是普通用户只能改一次,你拿root用户测试最好范围是-20到19也就是进程的优先级是[60,99]为什么是这个范围,为什么不能随便改?这就和里面结构有关系,不能随便改是因为我们的Linux系统是分时系统:就是给进程分配时间片,让每个进程都能均衡的在一段时间中得到CPU的资源举个例子:你在食堂排队你被一个老师插队你不说什么,如果多个老师插队的话就对你们先来的不公平,因为你可能吃不到饭所以学校为了杜绝就不允许插队,这里也是一样的这样就能让每个进程都得到调度保证程序正常运行2.3竞争、独立、并行、并发• 竞争性:系统进程数⽬众多⽽CPU资源只有少量甚⾄1个,所以进程之间是 具有竞争属性的。为了高效完成任务更合理竞争相关资源便具有了优先级• 独⽴性:多进程运⾏需要独享各种资源多进程运⾏期间互不⼲扰• 并⾏:多个进程在多个CPU下分别同时进⾏运⾏这称之为并⾏• 并发:多个进程在⼀个CPU下采⽤进程切换的⽅式在⼀段时间之内让多个进程都得以推进称之为并发2.4进程切换CPU上下⽂切换其实际含义是任务切换,或者CPU寄存器切换。当多任务内核决定运⾏另外的任务时,它保存正在运⾏任务的当前状态,也就是CPU寄存器中的全部内容。这些内容被保存在任务⾃⼰的堆栈中,⼊栈⼯作完成后就把下⼀个将要运⾏的任务的当前状况从该任务的栈中重新装⼊CPU寄存器,并开始下⼀个任务的运⾏,这⼀过程就是contextswitch三、进程的调度3.1组织进程我们以前是在描述进程,现在我们要把它组织起来,很显然组织进程用的是双链表结构,但是与我们的平常的双链表不同它是数据和结点分离的。我们定义的结点是structlist{intdata;//....很多属性structnode*next;structnode*prev而Linux进程的是把 next和prev单独用一个结构体封装,然后再在进程的结构体中定义带有这个结构体的变量一、为什么要这样设计呢?我们上篇文章讲到了其实每个进程是在一个调度队列里面,运行状态、阻塞状态、挂起状态等都是它们移到对应的队列中,但是其实都是进程到哪个队列都是这个进程,里面的大多数数据都没变,设计地每个队列的结构都是差不多的,为了提高代码的复用性,我们就把它们弄到一张双地链表中,就能只要维护链表中的一小块就能实现相应的操作如上图的一部分结构举例进程切换队列只需要把 PCB 内部嵌入的链表结点从旧队列双向链表中断开再插入目标队列的双向链表。仅仅修改节点的prev、next指针就完成进程在不同队列之间迁移不需要拷贝或者移动整个进程结构体。二、结构体的结点指针相同,那如何找到当前PCB在哪个队列中呢?我们知道在一个结构体中每个变量都是连续排布的,当然通过内存对齐规则可能中间会有空缺,但总体是连续的,我们可以通过(((type*))0-x)拿到x的地址,然后通过container_of宏拿到偏移量,因为我们知道,首个变量的地址就是整个结构体的地址,所以再拿x的地址-它的偏移量就能得到PCB的地址。并且我们还可以不用知道当前PCB的地址知道任意一个变量的地址就能反推到任意一个变量的地址3.2 Linux2.6内核进程O(1)调度队列这里讲进程被调度的核心属性queue[140]数组元素就是140个优先级进程• 普通优先级100〜139我们都是普通的优先级想想nice值的取值范围可与之对应• 实时优先级0〜99不关⼼当一个优先级过来,比如是默认的80,它会通过哈希映射加40然后找到对应的下标然后在每个下标用哈希桶给连接(可以是单链表、红黑树等结构),也就是说每个相同的优先级都会在一个桶里面那如何调度优先级呢?我们可能认为是直接循环遍历看哪个下标有没有进程,虽然是140个进程遍历其实也是大O(1),但是通过位图能更快的知道哪个下标的优先级有没有进程,可以详细看我这篇文章位图,拿32位整型当作检查每32个优先级是否有进程,然后再判断最先有1的优先级再去调度桶里的进程,因为本质位图是位运算位运算比循环和加减乘除都快,这样就相对增加了调度进程的效率也就是这个long bitmap[5]怎么解决饥饿问题呢?饥饿问题:就是我上面说的如果一直老师插队,也就是改变了NI值提高了优先级让其他优先级得不到CPU的资源,这就是饥饿问题其实是有struct prio_arry arry[2]也就是有两个优先级的结构体,一个是活跃队列一个是过期队列活跃队列:时间⽚还没有结束的所有进程都按照优先级放在该队列也就是说一个时间片会完成一轮的对所有优先级的调度过期队列:当前时间片结束的进程会在过期队列里与活跃队列相同的哈希映射下标中放入对应的进程进程轮换过程:首先,活跃队列每个优先级调度完都会放入对应过期队列中,当活跃队列全部调度完也就是完成了一轮调度然后通过*active-活跃队列指针它是指向活跃队列的,和*expired-过期指针,它是指过期队列的,把他们两个通过swap函数交换就可以进行下一轮的调度
返回列表