Linux 2.6 内核进程调度队列

Linux 2.6 内核进程调度队列

  • 运行队列(runqueue)
    • 蓝色区域(活动队列)
      • queue
      • bitmap
      • nr_active
      • 总结:时间片还没有结束的所有进程都按照优先级放在该队列(活动队列)
    • 红色区域(过期队列)
    • *active 和 *expired

Linux 内核究竟是如何调度队列的?

运行队列(runqueue)

在 OS 中会存在如下 运行队列,而每一个 CPU 都有一个这样的 运行队列

Linux 2.6 内核进程调度队列_第1张图片

蓝色区域(活动队列)

queue

注意此区域有一个叫 queue[140] 的东西,其真正的面目是这个:

task_struct* queue[140];

这是个数组,数组里是 task_struct* 类型的指针,可以存放 140 个进程 PCB 的地址

看似可以放 140 个,但实际上只会使用后 40 个([100, 139]),好像很巧合,进程优先级就是 40 个级别,对上了?
没错, queue 下标 100 对应优先级 60,下标 139 对应优先级 99([60, 99]

那么相同优先级的进程 PCBtask_struct)就会以链表的形式链入 queue 对应的下表处,看似是维护了一个运行队列,实际上是维护了 40 个队列(链表)

那么想要找到一个 r 状态进程,只需要找到 运行队列queue,从优先级最高的 60,也就是下表 100 处开始 遍历取出 即可

bitmap

我们的进程可能压根不会从下标 100 (优先级 60)的位置进行链入,可能都是下标 120 (优先级 80)的位置链入,那 CPU 还需要从下标 100 的位置开始遍历吗?那不是麻烦吗?

bitmap[5] 就出来了:

long bitmap[5];

long 在 32 位是 4 字节,32 个 bit,那 bitmap 数组的 5 个元素就有 5 * 32 = 160 个 bit

而就是用这 160 个 bit 表征 queue 里的 140 个指针是否有链入的进程,若 queue 某一下标有进程,那 bitmap 对应的位置上就是 1,反之则为 0

这样就能快速判断 queue 哪个下标位置上有进程,时间复杂度几近为 O(1)

nr_active

这个表示整个队列里有多少个进程,不用详述

总结:时间片还没有结束的所有进程都按照优先级放在该队列(活动队列)

红色区域(过期队列)

我们看了 蓝色区域queue 等属性,不是这 红色区域 属性怎么和它一样是怎么回事

实际上 运行队列 会出现两套这样的结构;
queuebitmapnr_active 可以放一起成为一个小的结构体作为 运行队列 里的一个属性

利用这个小的结构体构建一个只有两个这种数据结构元素的数组,分别为: array[0]array[1]

而上图 array[0] 表示蓝色区域, array[1] 表示红色区域

  • 过期队列活动队列 结构一模一样
  • 过期队列 上放置的进程,都是时间片耗尽的进程
  • 活动队列 上的进程都被处理完毕之后,会对 过期队列 的进程进行时间片重新计算

*active 和 *expired

CPU 在找进程时不是直接访问这个队列的,而是先找 active 指针,active 指针指向 array 数组的哪一个元素就访问哪一个元素里的 queue ,CPU 始终调度 active 指向的队列

active 所指的队列是 只出不进 的, expired 所指的队列是 只进不出

也就是说新来的进程是只入 expired 队列, active 队列里某个进程被调度的时间片到了,也是直接入 expired 队列,直到 active 队列为空,没有进程被调度时, OS 直接将指针 activeexpired 的内容交换即可

这就是 O(1) 调度算法,在系统当中查找一个最合适调度的进程的时间复杂度是一个常数,不随着进程增多而导致时间成本增加

  • active 指针永远指向 活动队列
  • expired 指针永远指向 过期队列
  • 可是 活动队列 上的进程会越来越少, 过期队列 上的进程会越来越多,因为进程时间片到期时一直都存在的
  • 没关系,在合适的时候,只要能够交换 active 指针和 expired 指针的内容,就相当于有具有了一批新的 活动进程

你可能感兴趣的:(Linux,linux,运维,服务器)