欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 焦点 > Linux:进程:进程调度

Linux:进程:进程调度

2025/4/19 16:56:53 来源:https://blog.csdn.net/2301_80641185/article/details/147309202  浏览:    关键词:Linux:进程:进程调度

进程在CPU上运行具有以下特性:

竞争、独⽴、并⾏、并发

竞争性:系统进程数⽬众多,⽽CPU资源很少甚至只有一个,所以进程之间是具有竞争属性的。为 了⾼效完成任务,更合理竞争相关资源,便具有了优先级

独⽴性:

为了避免一个进程出问题而导致其他进程出现连锁反应,进程之间在一定程度上相互独立,即使是父进程和子进程也是如此

并⾏:有同时多个进程被多个CPU调度运行,这种关系就叫做并行

并发:多个进程在⼀个CPU下采⽤进程切换的⽅式,在⼀段时间之内,让多个进程都得以推进,称 之为并发

基于以上特性,我们要对进程进行调度

进程调度依赖于进程优先级,要了解进程是如何调度的,我们需要先了解进程优先级的规则:

时间片

即CPU分配给该进程允许运行的时间,使各个进程从表面上看是同时进行的。

如果在时间片结束时进程还在运行,则CPU将被剥夺并分配给另一个进程。

如果进程在时间片结束前阻塞或结束,则CPU当即进行切换。而不会造成CPU资源浪费。

在宏观上:我们可以同时运行多个进程,每个进程并行不悖,同时运行。

但在微观上:由于只有一个CPU,一段时间内只能运行一个进程,如何处理公平,一种方法就是引入时间片,让每个进程轮流运行。

进程切换

首先,CPU的构成中有许多的寄存器,这些寄存器保存着当前运行的进程的数据。

寄存器被所有进程共享,寄存器内的数据,是属于当前运行进程的,这个数据也被称为 — 上下文数据

当操作系统想要运行一个进程,会将对应进程PCB地址传给CPU的某一个寄存器。让CPU能找到这个进程PCB,从而找到对应代码和数据。

当进程运行将指令传给CPU,CPU靠指令集分析指令运行对应代码,当进程的时间片结束后,操作系统将保存此时CPU中寄存器内的数据,当再次轮到这个进程后操作系统将原本数据加载到寄存器中,eip就可以通过下一条指令地址让代码继续运行。

进程退出CPU,操作系统保留寄存器里的数据,进程回到CPU,操作系统将原本数据恢复到寄存器中。这就完成了进程切换。

进程优先级

Linux进程的优先级是用来确定在多个进程同时运行时,哪个进程会获得更多的CPU时间片

Linux进程的优先级分为实时优先级和普通优先级。

我们不需要关心实时优先级,只需关注普通优先级即可

查看系统进程

在linux系统中,⽤ps ‒l命令则会输出以下内容:

  

• UID:代表执⾏者的⾝份

• PID:代表这个进程的代号

• PPID:代表⽗进程的代号

• PRI:代表这个进程可被执⾏的优先级,其值越⼩越早被执⾏,普通进程的PRI的范围为[60,99]

• NI:代表这个进程的nice值

nice值

nice值用于调整PRI,其方法为:PRI(old)=PRI(new)+nice(PRI默认为80)

所以,在Linux系统中,调整进程优先级,就是调整进程nice值

nice其取值范围是-20⾄19,⼀共40个级别,对应了普通进程的PRI范围

实例:修改进程11835的nice值,进而改变PRI

 

普通进程向用户显示的PRI的范围为[60,99],经内核处理为[100,139]:

​ 

下面介绍如何通过优先级来调度进程

Linux2.6内核:进程O(1)调度队列

在内核中有一个名为runqueue的数据结构负责进程的调度,

其中有一个类型为task_struct的指针数组queue[140]

而queue[i]为PRI为i的task_struct链表的头节点

CPU空闲时,就可以遍历这个指针数组,找到第一个不为空的节点并沿着这条链表执行

当然,遍历数组效率较低,所以实际是通过位图(bitmap)来实现的:

即bitmap[5]是一个整形数组,大小为160bit,我们只需要前120个bit,每一个bit对应一个queue[i],1表示queue[i]不为空,0表示为空,这样我们可以通过高效的位运算来找到PRI最低的task_struct链表

饥饿问题

刚才的调度队列存在一个问题:

如果一个进程的PRI很高,而此时又不断地有PRI较低的进程被创建,那么新创建的进程总是会

先于该进程被CPU运行,导致该进程一直无法被执行,这就是进程的饥饿问题

为了解决这个问题,Linux在一个runqueue里维护了两个队列:活动队列和过期队列,具体实现是将表示队列内进程数量的nr_active和queue[140]和bitmap[5]组成一个新的数据结构struct q,并在runqueue内定义一个struct q数组array[2], 

其中array[0]为活跃队列,由指针active维护,而array[1]为过期队列,由指针expired维护

CPU通过active指针和expired指针来访问活动队列和过期队列

CPU空闲时,总是从活动队列中寻找优先级最高的进程来执行

当活动队列为空时,会直接将active指针和expired指针交换

新进程或是在CPU上执行时时间片用完,被CPU剥离的进程会进入过期队列

这就在很大程度上避免了饥饿问题

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词