Linux学习之路 --- 进程篇 -- 进程调度和切换

在正式介绍进程调度之前,我们先了解一些概念。

现在的进程运行,是必须在cpu上把进程的代码跑完吗?肯定不是,要不然我们平时写的死循环就会一直运行下去,且我们的其他程序无法运行。显然这是不成立的,现代操作系统都是基于时间片进行轮转运行的。

下面再了解一些概念:

1.竞争性:系统运行的进程数目众多,而cpu资源只有少量,甚至只有一个,所以进程之间是具有竞争属性的,为了高效完成任务,更合理竞争相关资源,便具有了优先级。

2.独立性:多进程运行,需要独享各种资源,多进程运行期间互不干扰。(这点很重要)

3.并性:多个进程再多个cpu下分别,同时进行运行,这称之为并行。

4.并发:多个进程在一个CPU下采用进程切换的方式,在这一段时间内,让多个进程得以推进,称之为并发。

目录

一、进程切换

二、进程调度

1、queue

2.int bitmap[5]

3.nr_active

4.为什么有两个queue,bitmap,nr_active?

5.active ,expired指针


一、进程切换

这里先画张图帮助大家理解

每一个CPU都有一个运行队列(就绪队列),当进程准备号运行时,就会被加入到该队列里面,而我们的cpu会依次运行队列上的进程,时间片用完,就切换成下一个进程。进程在运行时,会产生大量的临时数据,而这些临时数据就保存在CPU的寄存器上,CPU上有许多的寄存器(eax,ebx,eip......),这些寄存器存放了当前进程的运行情况,而这些数据我们叫做进程的硬件上下文。正常情况下,一个时间片内,进程是不太能被运行完的。所以,我们就需要保存当前进程的临时数据,方便下次运行。这里的临时数据一般有进程自己来保存(保存过程其实挺复杂的),我们简化一下过程,可以把这些数据看作是放在进程独立控制的一小块内存中。一个进程时间片结束后,把进程重新放入cpu的就绪队列中(这里的就绪队列不一定是以链表的形式实现的,还有可能是数组或红黑树)。下一个进程开始运行,此时寄存器上存放的数据是前一个进程留下的,对于当前进程来说,这个数据就是无效的,所以我们可以直接覆盖写入。当然,如果这个进程不是第一次在cpu上运行,进程就会把之前的临时数据恢复到寄存器上,这样,cpu就可以继续从上一次执行到的代码处开始执行,这个过程也可以称为对曾今保存的硬件上下文进行恢复。

这里需要特别注意的是。CPU内部的寄存器只有一套,寄存器内部保存的数据是可以有很多套的,虽然寄存器数据放在了一个共享的cpu设备上,但是所有的数据都是被进程私有的。

二、进程调度

本文主要介绍基于分时的调度算法,实时算法不做着重的介绍。先介绍一下这两的区别,简单理解一下,第一个算法是让每一个进程都运行一会,第二个算法是让一个进程运行完,再让下一个进程运行。第一个一般我们也叫CFS调度算法。

这里我们着重介绍第一个进程调度的算法,我们先理解一下struct runqueue q

在这个结构体内部有几个地方是我们本文要着重介绍的,也就是我写出来的那几个成员变量。

1、queue

我们先了解一下queue,这个queue是一个大小为140的task_struct* 数组,我们暂时不用0 - 99 的元素,这里的下标其实代表的是优先级,而0 - 99 的优先级是实时优先级的范围,这个暂不处于我们考虑的范围,所以我们先介绍后面40个优先级,为啥是40呢? 其实这和前面介绍的nice值有一定的关系,普通进程的优先级范围大小就是40,所以这里我们也就用40个元素下标来表示。每一个优先级都有维护着一个队列,我们只要把对应优先级的进程的task_struct 挂在对应优先级的队列里即可,cpu会根据对应优先级大小依次运行每个优先队列就可以了。

2.int bitmap[5]

如果我们每次运行,cpu都要遍历检测queue这个数组,查看对应下标的队列是否有元素。虽然时间复杂度是O(1),但是这样还是挺不方便的,所以内核提供了一个int bitmap[5] 的数组来表示哪个元素是空,哪个元素上有需要运行的进程的task_struct。这里的表示方式就是用比特位的方式来表示哪个位置为空(比特位为零就表示空)。这里有5个int类型,所以有160个比特位,我们只要对这个数组做位运算即可,位运算的效率比遍历整个数组肯定是要高很多的。

计算方式:我们可以先看第一个整数是否位零,如果为零,表示0-31这个优先级范围内是没有进程需要运行,我们直接跳到下一个int即可,当有一个int不为0时,我们可以具体查看哪些比特位不为零,加上32 * (当前int下标 - 1)就是对应优先级数,也是queue的下标数。

3.nr_active

表示的是在queue维护的那么多队列中的活跃进程,这个不做着重介绍,了解即可

4.为什么有两个queue,bitmap,nr_active?

这里就涉及到了活跃队列和过期队列,试想一下,如果我们只维护一个queue,那么我们每次运行行完一个进程后就把重新放在该优先级的队列中,这样就会导致某一个高优先级队列一直运行,而低的优先级队列始终得不到运行,这就会造成进程饥饿问题。为了解决这个问题,系统就再建立了一个queue,这个queue叫做过期队列,而前面正在运行进程的queue叫做活跃队列,每次我们把运行队列里运行完的进程放在过期队列相应的优先级队列中,中间如果有进程加入,也是放在过期队列之中。然后在活跃队列运行完后,活跃队列变成过期队列,将过期队列变为活跃队列,循环往复。

5.active ,expired指针

我们可以把上面的两个队列用结构体封装起来,并设立一个大小为2的结构体数组,一个为活跃队列,另一个为过期队列。再用acitve和expired两个指针分别指向两个对列,active就表示活跃,expired表示过期。操作系统一直都是用acitve指针获取运行队列的信息。如果我们要将活跃队列变过期队列,将两个指针指向的内容进行交换即可。

文中如有不足之处,还望各位大佬指正,谢谢!!!

  • 16
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值