Linux: 进程的调度
查看进程优先级
再Linux系统中,我们可以用以下指令查看进程优先级
ps -la
先写一个死循环程序
#include<stdio.h>
#include<unistd.h>
int main()
{while(1){printf("我是一个子进程\n");sleep(1);}
}
运行这个程序 并且查询程序优先级
其中有两个重要的参数,分别是PRI和NI分别对应单词是priority和nice
PRI对应的就是进程优先级,PRI越小进程优先级越高,80是系统默认的优先级,PRI取值范围在
[60,99]这40个级别,为什么只设置40个级别,是因为防止有些进程优先级过高,导致一些优先级低的进程长时间得不到运行,造成进程饥饿
修改进程优先级
进程优先级满足一个运算公式
PRI=80+NI
要修改一个进程的优先级,那么我们就要通过调整NI来进行修改
我们来尝试修改一个进程的优先级
我们先运行我们之前的进程
ps -la //获取进程优先级及其PID
然后我们输入top命令
top
我们修改进程优先级,所以我们输入r
提示我们需要修改的是那个进程的PID,我们输入对应进程的PID即可
在输入我们想要的NI大小
再查看进程优先级大小
此时我们就通过修改NI的方式来修改了PRI
Linux内核进程调度队列
CPU中存在大量的寄存器,我们以一些常用的寄存器来举例子
eax/ebx/ecx/edx 用于存储临时数据,比如函数返回值
eds/ecs/fg/gs 段寄存器,用于区分代码和数据
eip 指针用于指明代码进行到那个位置
浮点数寄存器:浮点数运算
esp/ebp 构建栈区
程序在运行时,会产生非常多的数据,比如代码执行到那一块,代码输出了什么结果,定义了什么变量,这些数据,这种操作我们称作硬件上下文,
当我们进程执行结束,进程需要退出CPU时,进程再运行过程中产生的数据都会存储到进程的PCB中,这种操作我们称为保护上下文。
当我们进程再次加载到CPU时,我们需要将我们之前执行进程产生的数据都拷贝给CPU,这种操作我们称为恢复上下文
我们来看看运行队列时如何调度的
Linux系统通过run_queue队列来调用进程
蓝色部分和红色部分是最重要的两个部分
我们先来看红色部分
queue是运行队列,其中0~99是正在运行的节点数,100~139是等待运行的节点数
nractive是一个整形,它用于记录queue里面有多少个位置是有数据的
bitmap[5]是一个位图,它有5个int数据,这5个int有每个有4个字节,对应160个比特位
这160个比特位里有140个比特位对应queue的140个数据
如果比特位为1则表示queue对应的位置有数据,如果比特位为0,那么对应的queue没有数据
queue是一个指针数组,每个指针对应一个链表,CPU从第100个开始将数据写入CPU运行
那么为什么会有两个表呢
这两个表可以有效解决饥饿问题,CPU会先执行一个表里面的进程,当这个表的进程执行完毕后,CPU会换另外一个表继续进行运算,红色的表执行完了,换蓝色的表,再某个表在执行的时候,不会将新的进程加载到正在执行进程的表中,会进程加载到另外一个表中,这样就解决了进程饥饿的问题
当我们只有run_queue,如果有一个进程优先级为70,那么如果一直有优先级为70的进程进入到这个表中,那么这个进程就会长时间得不到CPU的资源,就会造成进程饥饿问题,所以我们将新的进程链入另外一个表中,就能有效防止这种问题的产生
active指向是活跃进程队列,expired指向的是过期进程队列
CPU只执行活跃进程队列,过期进程队列用来存储新的进程
当活跃进程队列运行完毕,活跃进程队列变为过期进程队列