进程优先级、进程调度以及Linux2.6内核进程调度队列

文章目录

  • 一.进程优先级
    • 优先级概念
    • Linux下的进程优先级
  • 二.进程调度
    • 调度的概念
    • Linux的进程切换与调度
      • 进程切换
      • 进程调度

一.进程优先级

优先级概念

由于操作系统具有共享性,操作系统的资源是共享的,当多个进程要访问同一个资源,需要通过一定方式来确定访问顺序,优先级就是进程获取资源的先后顺序。

CPU资源分配的先后顺序,就是指进程的优先权。优先权高的进程有优先执行的权力。配置优先权对多任务环境的Linux很有用,可以改善系统性能。还可以把进程运行到指定CPU上,这样一来,把不重要的进程安排到某个CPU,可以大大改善系统整体性能。

操作系统中资源是有限的,相对于进程的数量总是少的,那么进程竞争资源是常态,这就引入了优先级来对不同进程进行评判,以此能更有条理地调度进程。

Linux下的进程优先级

优先级是进程的一个属性,那么其也是在进程PCB中,可通过ps -l来进行查看

这里通过循环输入命令方便查看:

while :; do ps -la |head -1 && ps -la | grep myprocess ;sleep 1;echo ---------------------------------------------- ; done

这里有一个程序,运行后不断打印Hello

#include 
#include 
#include 

int main()
{
    while(1)
    {
        printf("Hello.\n");
        sleep(1);
    }
    return 0;
}

在shell中输入命令查看,得到以下结果

F S   UID     PID    PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 S     0  836593  836118  0  80   0 -   694 hrtime pts/0    00:00:00 myprocess

这里重点关注PRI和NI
Linux的进程优先级由PRI和NI组成。

PRI:优先级(Priority),数字越小优先级越高,默认80,范围[60,99]
NI:nice值,表示进程可被执行的优先级的修正数值,默认0,范围[-20,19]

进程的真正优先级=PRI+NI,这里的PRI不能直接进行修改,修改nice值更为妥当,同时nice值被覆盖写入

可通过top指令修改nice值:先使用top命令打开资源管理器,再按r指令进入进程值修改,最后输入进程PID后最后输入nice值。

修改前
F S   UID     PID    PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 S     0  840588  836118  0  80   0 -   694 hrtime pts/0    00:00:00 myprocess
----------------------------------------------
修改后
F S   UID     PID    PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 S     0  840588  836118  0  90  10 -   694 hrtime pts/0    00:00:00 myprocess
----------------------------------------------

二.进程调度

调度的概念

CPU调度是对CPU进行分配,即从就绪队列中按照一定的算法(公平、高效的原则)选择一个进程将CPU分配给它运行,以实现进程并发地执行。

一个作业从提交直到完成,往往要经历三级调度
进程优先级、进程调度以及Linux2.6内核进程调度队列_第1张图片

  • 进程调度(低级调度)
    实现了进程的切换和处理器的切换。使进程在就绪、运行、等待三态之间切换。

  • 内存调度(中级调度|平衡负载调度)
    主要涉及的资源是内存资源,主要涉及挂起和激活操作。

  • 作业调度(高级调度)
    高级调度涉及进程创建、就绪、运行、终止这些状态。

Linux的进程切换与调度

进程切换

CPU会维护一个调度队列runqueque,进程在调度队列中进行排队等待操作系统分配CPU执行。
进程优先级、进程调度以及Linux2.6内核进程调度队列_第2张图片

同时,CPU中会存在大量寄存器,在进程运行过程中会产生大量临时数据放到CPU寄存器中。
当一个进程的时间片结束,需要进行进程切换,这时就要把寄存器中的数据保存在task_struct中,这些CPU内部的所有临时数据也叫进程硬件上下文。当第二次该进程被调度,就会将曾经保存的硬件上下文进行恢复。

所有的保存是为了最终数据的恢复,所有的恢复都是为了继续上次的运行。

进程调度

Linux进程调度算法是基于时间片的,同时考虑优先级、饥饿和效率
首先下面是调度队列runqueque的数据结构
进程优先级、进程调度以及Linux2.6内核进程调度队列_第3张图片

其中队列是一个task_struct*数组维护的,为queue[140],一共140个优先级,每个优先级对应一个队列,对应一个数组元素。0-99为实时优先级,这里不用关心。需要关心的是100-139这40个优先级,刚好对应nice的取值范围。

时间片还没有结束的所有进程都按照优先级放在该队列,nr_active用于记录总共有多少个运行状态的进程。

当要按优先级取出先来的进程时,要在queue[140]检测每个队列是否有进程,显然从头遍历的复杂度太高。这里加入一个数组:int bitmap[5]int有32位,那么整个数组共有32*5 = 160个比特位,刚好覆盖140,比特位的位置表示对应优先级的队列,比特位的内容表示该队列是否为空。这样就能实现O(1)的时间复杂度进行调度。

以上三个成员构成一个结构体

struct q{
    int nr_active;
    int bitmap[5];
    task_struct *queue[140];
};

runqueue中就有一个struct q* array[2]的数组,同时维护两个指针activeexpired分别轮流指向该数组的两个元素。
active永远指向活动队列,expired永远指向过期队列,活动队列上的进程会越来越少,过期队列上的进程会越来越多,当活动队列上没有任何进程时,只需要Swap(active, expired)交换两指针指向的元素空间,过期队列变成活动队列,活动队列变成过期队列,周而复始。

你可能感兴趣的:(Linux系统编程及网络编程,linux,服务器)