一、进程优先级
1.优先级的概念
进程要访问某种资源,要进行进程上的排队,来确认享受资源的前后顺序。
在xshell中我们可以通过ps -la指令对所有进程进行信息查询,其中PRI那一列显示的就是进程的优先级序号。
2.优先级的实现
通过上面的查询界面我们可以看到,进程的优先级是通过一个整形变量来表示的,这个整形在存储上属于pcb的范畴。所以我们调整优先级也是通过调整pri最终的值来实现的。
pri值是有范围限定的最小是小于等于60,最大是99,系统默认的pri值是80。而为什么要对优先级的数值进行限制呢?因为我们如果不加限制的话,就有有人使用更小或者更大的数打破这个平衡,导致一些常规进程很难能够得到资源。
二、进程的调度和切换
1.Linux的进程调度概念
我们先来熟悉几个概念:
1.进程在调度的时候不是一个程序执行完之后才能执行下一个,而是通过时间片进行轮转。
2.竞争性:系统要运行的进程数目众多,而CPU只有一个,所以各个进程之间是具有竞争性的,为了更高效的完成任务,所以才有了优先级的存在。
3.独立性:各个进程之间是独享资源的,进程之间的工作是互不干扰的
4.并行:多个进程在多个CPU之下进行执行。
5.并发:多个进程在一个CPU之下进行执行。通过进程切换的方式让多个进程近似于同时推进。
2.进程的切换
1.硬件上下文
要了解进程的切换,第一步就是要了解内部的数据是怎么进行切换和保存的。
在CPU的内部,其实存有大量的寄存器,比如eax,ebx…是用来保存变量的,eip是程序计数器,用来保存程序进度的,eds是衡量代码区域的等等。这些寄存器就是存储围绕在CPU上运行的程序产生的临时变量,当程序运行结束之后返回内存。而从寄存器中转移出来的关于进程的数据就是这个进程的硬件上下文。在进程结束之后,上下文数据被保存在pcb中,用来保护上下文数据。下一个进程切换上来之后,直接用pcb中的上下文数据进行覆盖即可。
2.Linux调度实现
如图所示,是Linux内核中进程排列的数据结构,CPU进行进程调度也是通过这个数据结构进行。我们可以看到,关于进程的排序队列有两个,一个是array[0]活跃进程一个是array[1]过期进程,正是通过这两个结构体来控制所有等待运行的进程。接下来,我们来详细看一下这个结构体中的三个成员变量到底是有什么含义。
首先我们先看最后一个成员变量,是一个变量为pcb指针类型的对列,其中有140个对象,这140个对象可不是正在等待运行的进程,而是分别对应140个不同优先级的对象队列,这些队列中间会有很多相同优先级的队列。也就是说CPU并不是简单的在管理一个队列,而是在管理140个队列!队列的序号是按优先级的序号进行排序的,但是在我们第一个内容讲的优先级顺序不是只有40个吗,为什么这里可以安排140个指针呢?
因为这里有两种优先级,前100个都是实时操作优先级,只有后40才是分时操作优先级,前100个优先级不在本文的讨论范围内。每个队列的所有进程优先级相等,按照顺序即可。
然后我们来看第二个成员变量,第二个是一个int类型的数组,一共有160个比特位的大小,该数组就是使用这160个比特位的内容进行表示队列是否为空,通过位运算来检测所有队列是否为空,这样可以大大提高检测的效率。
最上面的变量也是一个int类型的变量,是表示目前有多少个运行状态的进程。
就是这三个变量相互配合,才能让操作系统在对进程进行调度的时候高效。大致配合是,先由nr_active确定队列中是否有运行状态的进程,一共有多少个,其次在通过bitmap[5]的位运算来对每个优先级的队列进行判断,是否为空。最后,找到每个相同优先级的队列,进行调用即可。
最后我们来区分一下这两个结构体的不同。首先我们注意到,在这两个结构体的上方,有两个指针。
这两个指针分别指向活跃和过期进程的结构体,其中过期队列中存储的是当CPU在调用活跃进程时,新加入进来的进程以及在进程调用时超出时间片范围的进程。但是随着时间的逐渐执行,活跃队列中的进程会逐渐减少,过期队列中的进程会逐渐增加。当活跃进程中的进程减少为0的时候,上方的两个指针就是发生互换,对于CPU来说,其实就是两种队列的内容发生了互换,因为CPU就是通过这两个指针来调用运行队列中的进程的。
创作不易,感谢阅读。