linux进程优先级——优先值、调度算法、进程性质

发布于:2024-07-22 ⋅ 阅读:(55) ⋅ 点赞:(0)

        前言:本篇内容主要讲解linux下进程的优先级。 优先级的内容相对较少, 最重要的内容就是cpu的调度方法。 内容相对容易理解。 

        ps:本节内容适合了解冯诺依曼和操作系统的管理方式以及进程PCB的友友们进程观看

进程的优先级是什么

        进程的优先级与进程的权限之间有什么区别——进程的权限指的是能不能被访问。 而进程的优先级指的是进程被访问的次序问题。

为什么要有进程的优先级

        因为cpu的空间归根结底还是寄存器, 而寄存器很小, 就注定了cpu的资源是有限的。 而进程的个数是多个的, 这就势必会导致进程之间的竞争关系!——之前提到了进程之间的独立性, 这次是竞争性, 关于进程之间的性质, 后续将会进行讲解。

        操作系统为了保证进程之间的良性竞争, 他就会确认进程之间的优先级。如果我们的进程长时间得不到cpu资源, 该进程的代码长时间得不到推进, 就会出现饥饿问题。——饥饿问题是什么? 比如我们运行一qq的时候, qq忽然没有相应了, 最后弹出一个弹窗,上面写着强行停止或者等待。这个时候, 其实就是qq长时间没有被执行, qq出现了的饥饿,这就是饥饿问题。 

怎样理解优先级

        优先级的查看就是ps al

        上面的PRI是进程的优先级, NI是nice值。PRI优先值越小, 优先级越高。PRI优先值越大, 优先级越小。

        下面是我们定义的一个程序:

        现在运行这个程序, 看一下进程的优先级:

        这个进程的优先值是20, nice值是0——这里的nice值是用来调整优先值的, nice值是0, 也就是说进程的优先值经过调整nice后是20。 如果这里的nice值是1,PRI是20,  那么就是说进程的优先值经过调整1后是20, 也就是说原本是19. ——而对于操作系统来说, 操作系统不可能让进程无限的调整优先值, 否则进程之间的运动顺序就会非常乱。 所以, 一般进程的nice值都有一个范围, 这个范围是[-20, 19]. 也就是说, 对于这个程序的优先值来说, 它的最大范围就是[0, 39]。

        现在看一下UID, UID是这个程序的拥有者的编号。 像上图的UID是1000, 就说明我们当前用户的编号也就是UID是1000. 

        而我们如何查看UID? 就是使用ls -n, 其中-n选项就是将文件夹的拥有者等换成对应的编号。

操作系统如何根据优先级展开调度

        首先, 对于cpu来说, cpu有一个runqueue, 我们知道, 进程都会链接到runqueue里面, 而runqueue是一个双链表。 那么对于cpu来说,是如何确认优先级呢?

        首先, 我们可以假设cpu里面的一个runqueue结构体, 里面的XXX指向即确认优先级即将执行的队列, YYY指向等待区(这个等待区是等待XXX全部执行完然后替换XXX, 具体接下来会讲到, 这个三言两语不好说清)的队列:

在上面两个指针数组里面, 0~99的内容是不用的,留给其他进程使用。 而100~139是正好40个元素, 这40个元素分别指向了一个对应的优先值。——我们知道, 进程的优先值的假如是80, 那么经过nice变换后, 变换的范围就是[60,, 99], 进程的优先级假如是60, 那么经过nice变换后, 变换的范围就是[40, 79]。 也就是说, 这些进程的优先值变化范围都是40, 正好对应了数组指针的40个元素。 ——在底层这些指针数组其实就是维护了一个个对应优先值的进程PCB, 如下图:

        上面进程的优先级的本质其实就是开散列哈希。 对于同一个优先级的进程先取离头部近的进程。 而之所以优先值越低, 进程的优先级越高的原因就是优先值对应指针数组的下标。 而下标越低, 地址越低, cpu越先取到。

        而运行队列里面维护者两个开散列哈希, 假设分别是XXX, YYY, 并且这两个开散列哈希都有一个指向他们的二级指针维护, 就比如下图:

        二级指针X用来维护XXX, 二级指针Y用来维护YYY数组。 而之所以要有两个指针数组, 是因为对于操作系统来说, 他要执行程序, 就必须先找到X, 然后再找到XXX, 进而找到指向的PCB, 然后执行队列里面进程。 之后再来新的进程的时候, 就放到等待队列里面。 等到XXX指向的数组的进程运行完毕之后, 就交换两个指针的内容。 也就是Swap(&X, &Y)。

        其中的调用细节就是使用了位图:bitmap映射XXX, YYY两个数组里面的所有元素。 只要这个元素有元素, 就将位图对应的比特位映射1, 否则映射0——这就是linux内核2.6版本的O(1)调度算法!

        所以, 我们知道, 运行队列的调度本质就是将进程的PCB按照优先级打散到XXX或者YYY的不同位置, 而位置的不同, 就意味着调度顺序的不同, 所以, 对于cpu来说, 就能使用调度算法根据进程的优先级调度这些进程了!

进程的各种性质

        竞争性:现在我们来看一下进程的竞争性, 为什么说队列具有竞争性,因为对于整个冯诺依曼来说, 内存里面的进程是非常的多的。而cpu只有一个, 而像那些底层硬件, 通常也只有一个或者几个。这些硬件的资源都是非常稀缺的, 那么就势必造成进程在硬件的等待队列里的时候一定要确认优先级。而确认优先级的本质就是在竞争。——这就是进程的竞争性。 

        独立性,进程在设计的时候, 就是按照进程之间互不影响进行设计的, 也就是说, 一个进程崩溃了,睡眠了, 运行了等等不会影响其他进程。 就比如我们现实生活中使用qq, qq崩溃了并不影响我们微信的运行。

        并行:并行是两个或者多个进程同时运行, 这个概念存在于cpu存在多个。 如果cpu有两个或者两个以上,那么每个cpu都有一个运行队列, 这些运行队列都会确认优先级, 然后根据O(1)的调度算法调度进程运行, 这就是并行。

        并发:对于并发来说, 并发是存在于一个cpu中, cpu对于多个进程根据时间片的规定按照运行队列确认优先级, 一次进行调度。 让不同的进程同时推进的过程, 这个过程就叫做并发——之所以会这样是因为对于cpu来说, 它的切换速度太快了, 纳秒级别, 我们人是感觉不到的。进程切换 + 时间片——》基于进程切换, 基于时间片轮转的调度算法。那么, 现在有一个问题, 对于时间片轮换调度来说, 如果一个进程执行完了那么它会被继续放到等待队列里面, 那么这就势必会造成这个进程又排到了那些没有被执行过的, 但是优先级很低的进程前面。 所以,为了防止出现饥饿问题,当一个进程时间到了后, 他不会放到调度队列里面——也就是上面的XXX, 而是放到等待队列里面——也就是YYY, 当XXX运行完了, YYY就变成调度队列, 对YYY里面的进程进程调度。 :

        


网站公告

今日签到

点亮在社区的每一天
去签到