目录
前言
本篇文章是Linux进程系列中的最后一篇文章,本来是想放在上一篇文章的结尾的,但是想了想还是单独写一篇文章吧,虽然说这部分内容是比较难的,所有一般来说是简单的提及带过的,但是为了让大家对进程有更深的理解与认识,还是看了一些别人的文章,然后学习了学习,然后对此做了总结,尽可能详细的介绍明白。
运行队列runqueue
首先先简单的介绍一下runqueue
runqueue 代表了一个 CPU 的就绪队列,其中包含了多个进程的 task_struct(即进程控制块)。在 Linux 等操作系统中,每个 CPU 都会有一个独立的 runqueue,用来管理该 CPU 上的所有就绪进程。每个 task_struct 存储了该进程的状态、调度信息等。
当有多个 CPU 时,进程的负载均衡问题确实是一个重要的考虑因素。操作系统通常会通过负载均衡策略将进程分配到不同的 CPU 上,以避免某些 CPU 过载而其他 CPU 处于空闲状态。
Linux 等现代操作系统会定期通过进程迁移等手段实现负载均衡,确保各个 CPU 的负载较为均衡,从而提高系统的整体效率。
你说的“分时操作系统,调度时强调的是公平性”是正确的。在分时系统中,调度的核心目标之一是公平性,即尽量保证每个进程能够在合理的时间内获得 CPU 时间片。调度算法(比如轮转法、优先级调度等)都是为了保证这种公平性,避免某些进程长时间得不到执行。
这种公平性通常意味着“每个进程的执行时间应该大致相等”,即使是用户进程,也会得到相对平等的 CPU 时间,而不是长期被某个进程或线程独占。
当你提到“实时操作系统,调度时强调的是实时性”,这个说法是准确的。实时操作系统(RTOS)与分时操作系统的不同之处在于,它的调度目标是保证任务在规定的时间内完成,而不仅仅是公平性。
实时性调度更侧重于时间约束,确保任务按照严格的时间要求进行执行,这对于一些实时应用(如智能驾驶、自动化控制等)至关重要。实时操作系统有不同的调度算法,如抢占式优先级调度、周期性调度等,来确保任务的实时性。
活跃队列&过期队列
PU调度时,需要把进程拿走的同时,把正在执行的进程剥离下来(被放入运行队列)
运行队列中存在两套相同的结构体类型。
拿走的队列:活跃队列。放入队列:过期队列。
活跃队列表示当前CPU正在执行的运行队列,而正在执行的运行队列(也就是活跃队列)是不可以增加新的进程的 。
与此同时,操作系统设置了一个 和活跃队列相同属性的过期队列,当活跃队列正在执行时如果有进程需要添加进运行队列,那么就会添加至过期队列当中,也就是说 活跃队列的进程一直在减少,而过期队列中的进程一直在增多!
活跃队列是只出不进
过期队列是只进不出
两个队列是被存放在结构体数组中的,结构体数组存放在运行队列中
且运行队列中存在active指针和expired指针分别指向活跃队列和过期队列。
时间片还没有结束的所有进程都按照优先级放在该队列
nr_active: 总共有多少个运行状态的进程
queue[140]: 一个元素就是一个进程队列,相同优先级的进程按照FIFO规则进行排队调度,所以,数组下标就是优先级!
从该结构中,选择一个最合适的进程,过程是怎么的呢?
从0下表开始遍历queue[140]
找到第一个非空队列,该队列必定为优先级最高的队列
拿到选中队列的第一个进程,开始运行,调度完成!
遍历queue[140]时间复杂度是常数!但还是太低效了!
bitmap[5]:一共140个优先级,一共140个进程队列,为了提高查找非空队列的效率,就可以用5*32个比特位表示队列是否为空,这样,便可以大大提高查找效率!
过期队列和活动队列结构一模一样
过期队列上放置的进程,都是时间片耗尽的进程
当活动队列上的进程都被处理完毕之后,对过期队列的进程进行时间片重新计算
bitmap[5]&O(1)调度算法
long bitmap[5],因为long为4字节,所有5个一共有845=160个bite位.
但是我们一个队列只有140个,所以使用位图bitmap绰绰有余,所以我们就使用位图的思想,来表示这个位置的队列有无进程PCB。
0表示无,1表示有。
所以,CPU不需要遍历140的队列数组,只需要遍历bitmap的5个位置,遍历一次就查找了32个bite位,大大提高了效率!
时间复杂度位O(1),所以O(1)调度算法!
nr_active
调度:nr_active 影响调度器选择哪个进程执行。
负载均衡:如果某个 CPU 核心的 nr_active 很高,调度器会把一些进程迁移到负载较低的核心上。
nr_active 是 Linux 用来管理进程负载和调度的工具。
在 Windows 中,多核调度和任务迁移的机制类似,也有负载均衡的功能。
active指针和expired指针
active指针通常指向当前活跃的任务或进程。活跃任务是指那些已经准备好运行但尚未被调度器选中的进程。这些进程通常位于CPU的运行队列中,等待调度器的调度。active指针帮助内核快速定位并调度这些活跃进程。
expired指针则用于管理那些已经超过其运行时间限制或因为其他原因而被标记为“过期”的进程。这些进程不再处于活跃状态,但仍然需要被适当地处理,例如可能需要被唤醒或重新调度。expired指针帮助内核跟踪这些过期的进程,以便在需要时进行处理。
active指针永远指向活动队列
expired指针永远指向过期队列
CPU正在执行访问的队列是active指向的A活跃队列(只出不进)
另外一个被expired指向的结构相同的过期队列B(只进不出)
新创建的进程的PCB只链接到过期队列B
CPU调度的活跃队列A中的进程PCB被CPU调度时间片到了之后,也链接到过期队列B
最后A队列中的进程被CPU全部调度完/处理完,B队列也满满的
接着将两个active指针和expired指针交换swap(active,expired),交换的是指针内容
重复上诉过程
最后总结
如果上面的介绍有帮助的话,还请点赞,如果有不明白的还请谅解。
最后推荐一篇文章Linux的进程优先级 NI 和 PR - 简书