【Linux】进程周边004之进程的调度与切换(领略Linux系统进程调度算法的神奇)

 

👀樊梓慕:个人主页

 🎥个人专栏:《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C++》《Linux》

🌝每一个不曾起舞的日子,都是对生命的辜负


目录

前言

1.进程切换

2.进程调度

2.1Linux系统的进程调度算法如何实现兼顾进程优先级的设计

2.2Linux系统的进程调度算法如何实现兼顾效率的设计

2.3nr_active

2.4Linux系统的进程调度算法如何实现兼顾进程饥饿的设计

2.4.1理论上讲解

2.4.2如何实现的?


前言

上篇文章我们最后提到了进程的并发:多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发。

那么Linux是如何完成进程的调度与切换的呢?

本篇文章博主会与大家共同学习Linux下进程的调度与切换。


 欢迎大家📂收藏📂以便未来做题时可以快速找到思路,巧妙的方法可以事半功倍。 

=========================================================================

GITEE相关代码:🌟fanfei_c的仓库🌟

=========================================================================


1.进程切换

我们知道一个CPU在同一时间只能运行一个进程,而并发实际上就是利用时间片,让每个进程在CPU上只能运行一个时间片的时间,然后就被切换到另一个进程,所以我们计算机虽然看起来似乎是非常流畅的运行每个进程,而实际上则是一卡一卡的运行的,只不过这个时间非常短,我们感觉不到罢了。

那进程首次调度完成被切换走,当CPU二次调度该进程时,是如何记得上次执行到哪里了呢?

CPU中存在有大量的寄存器,进程运行产生的临时数据都被保存在这些寄存器中,这些临时数据被称为进程的硬件上下文,当时间片消耗完的时候,进程会保存这些上下文,现阶段大家可以理解为保存到PCB中,当进程被二次调度时,进程会将曾经保存的硬件上下文进行恢复(将之前保存的硬件上下文覆盖到CPU的寄存器中)。

  • 虽然CPU中的寄存器只有一套,但是寄存器内部保存的数据可以有多套。
  • CPU是被所有进程共享的,但内部的数据却是进程私有的。

大家可以理解为:在任意一个时刻,CPU中的数据只属于一个进程。

所以看起来,我们用的是同一个设备,但实际上进程之间是具有独立性的。

独立性:进程运行需要独享各种资源,多进程运行期间互不干扰。

2.进程调度

上篇文章我们讲到了优先级的概念,那Linux是如何在兼顾进程优先级、饥饿、效率来实现进程调度的算法呢?

实际上操作系统想要实现一个进程调度算法并不容易,而Linux对于进程调度的算法设计非常优秀,我们一起来学习一下吧:

之前我们学习进程状态时,有关进程排队中CPU运行队列有过这样一张图:

今天我们来细化一下运行队列中的成员:


这是Linux系统下对运行队列的设计。

不考虑其他成员,我们只看圈出来的两个部分:

蓝色部分为活动队列,红色部分为过期队列,他们两个你可以认为是完全相同的两个结构。


2.1Linux系统的进程调度算法如何实现兼顾进程优先级的设计

该数组中一个元素就是一个进程队列,相同优先级的进程按照FIFO(先进先出)规则进行排队调度,所以,数组下标就是优先级!

但我们之前学习优先级时不是说进程优先级范围为[60,99]么,一共40个优先级,为什么这里有140个优先级呢?

首先这里我们只考虑100~139,这部分被称为普通优先级,100就对应着60,139就对应着99,而剩下0~99的部分为实时优先级

🔎什么是实时优先级?🔍

  • 分时操作系统必须以时间片为周期调度不同的进程,是为了确保公平,避免进程饥饿,比如现在的互联网,在互联网的视角中,所有用户都是公平的,不能因为谁的优先级高就仅服务谁,所有用户的优先级都差不太多,不会出现谁的优先级非常高的情况。
  • 还有另外一种为实时操作系统则相反,在运行某个进程时,必须跑完,严格按照队列先后顺序进行,如果有更高优先级的进程,允许插队,即实时操作系统必须对用户有高响应这一特性,比如车载系统,绝对不能使用基于时间片轮转的分时操作系统,而必须采用实时操作系统,刹车的指令优先级非常高,在用户需要刹车时他不会考虑音乐播放器进程会不会饥饿。
  • 所以我们必须保证一些进程实时尽快的被处理,所以也就有了实时优先级的概念,而0~99这些优先级就是为了这一部分而准备的。

 所以我们运行队列中queue[140]的构成大概为这样子:

之前我们以为运行队列就是一个队列,但实际上操作系统要给我们维护40个队列,每个队列都代表着不同的优先级。


2.2Linux系统的进程调度算法如何实现兼顾效率的设计

每次CPU运行进程,难道都要从开始向上遍历找不为空的队列么,那也太麻烦了。

所以就有了bitmap[5]这个成员,该成员是int类型的数组,int类型占32个bit,所以5个int就是160个bit,而queue为140,多出来的20我们不管,那是不是检测哪个优先级队列中有进程就能够转化乘检测对应的比特位是否为1了呢!?

位操作的速度可比遍历快多了。

比如:如果数组中某个元素为0,则证明该32个比特位都为0,也就证明该32个队列都为空,如果某个元素不为0,那该问题就转化为了如何从一个整形中提取出最低位的不为0的比特位。

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


2.3nr_active

表示该运行队列共有多少个活跃进程。


2.4Linux系统的进程调度算法如何实现兼顾进程饥饿的设计

假设在运行队列里存在有很多优先级为139的进程等待执行,但此时不断产生更高优先级的进程,也就导致优先级为139的进程进程饥饿的问题了。


2.4.1理论上讲解

那Linux系统是如何处理进程饥饿的呢?

Linux系统搞了两个一摸一样的结构就是为了处理进程饥饿。

一个称之为活跃队列,一个称之为过期队列。

CPU只会执行活跃队列中的进程,而新产生的进程会被操作系统添加到过期队列,不论这个新进程的优先级高低,等活跃队列中的进程都被执行完成了后,此时过期队列摇身一变成为活跃队列,而活跃队列变为过期队列,周而复始,也就解决了进程饥饿的问题。

注意:如果某个处在活跃队列中的进程的时间片消耗完,该进程就会从活跃队列中剥离,然后被添加到过期队列。


2.4.2如何实现的?

我们将蓝色框与红色框定义为两个结构体:

struct q//这两个结构体相同,这里就写一个大家理解就行
{int nr_active;int bitmap[5];task_struct queue[140];
}

再定义一个数组struct q array[2];

该数组用来存放这两个结构体。

再定义两个成员*active与*expired:


这两个指针分别指向数组中的内容,即:

struct q *active=&array[0];
struct q *expired=&array[1];

 每当活跃队列为空时,就会交换这两个指针变量的内容,使之指向对方原来指向的内容,这也就完成了活跃队列变为过期队列,过期队列变为活跃队列的操作:

swap(&active,&expired);

所以Linux系统对于进程调度的设计是不是非常巧妙呢!? 


=========================================================================

如果你对该系列文章有兴趣的话,欢迎持续关注博主动态,博主会持续输出优质内容

🍎博主很需要大家的支持,你的支持是我创作的不竭动力🍎

🌟~ 点赞收藏+关注 ~🌟

=========================================================================

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/224161.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Infobright列存数据库原理介绍

简介 Infobright 是一个面向 OLAP 场景的开源列存数据库。比较容易找到代码的版本是 Infobright Community Edition 4.0.7,大概是 2006 年前后的代码。2016 年6 月,Infobright 决定停止开源1。由于它同时提供企业版和社区版,开源版本的功能相…

基于ssm大学学术交流论坛论文

摘 要 随着科学技术的飞速发展,各行各业都在努力与现代先进技术接轨,通过科技手段提高自身的优势;对于大学学术交流论坛当然也不能排除在外,随着网络技术的不断成熟,带动了大学学术交流论坛的发展,它彻底改…

C# 图解教程 第5版 —— 第18章 泛型

文章目录 18.1 什么是泛型18.2 C# 中的泛型18.3 泛型类18.3.1 声明泛型类18.3.2 创建构造类型18.3.3 创建变量和实例18.3.4 使用泛型的示例18.3.5 比较泛型和非泛型栈 18.4 类型参数的约束18.4.1 Where 子句18.4.2 约束类型和次序 18.5 泛型方法18.5.1 声明泛型方法18.5.2 调用…

go-zero开发入门之网关往rpc服务传递数据1

go-zero 的网关往 rpc 服务传递数据时,可以使用 headers,但需要注意前缀规则,否则会发现数据传递不过去,或者对方取不到数据。 go-zero 的网关对服务的调用使用了第三方库 grpcurl,入口函数为 InvokeRPC: …

Linux系统中如何开启和配置OpenGauss数据库的远程连接

文章目录 前言1. Linux 安装 openGauss2. Linux 安装cpolar3. 创建openGauss主节点端口号公网地址4. 远程连接openGauss5. 固定连接TCP公网地址6. 固定地址连接测试7. 结语 前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍…

基于Maven构建OSGI应用(Maven和OSGI结合)

基于Maven构建OSGI应用。 使用Maven来构建项目,包括项目的创建、子模块buldle的创建等。使用OSGI来实现动态模块化管理,实现模块的热插拔效果(即插即用)。 创建一个Maven项目:helloworld,并在该项目下创建…

selenium/webdriver运行原理与机制

最近在看一些底层的东西。driver翻译过来是驱动,司机的意思。如果将webdriver比做成司机,竟然非常恰当。 我们可以把WebDriver驱动浏览器类比成出租车司机开出租车。在开出租车时有三个角色: 乘客:他/她告诉出租车司机去哪里&…

springboot_tomcat开启access log日志,监控打印每个请求地址和响应时间

springboot_tomcat开启access log日志,监控打印每个请求地址和响应时间 一、前言二、环境三、配置对应的对象信息四、AccessLog配置默认值及说明五、配置实例六、pattern参数组成说明七、常用的pattern配置7.1 pattern默认值7.2 默认配置说明7.3 打印请求、响应中co…

解决因找不到qt5core.dll文件而导致无法执行代码问题

Qt5core.dll是Qt5框架的核心模块,用于提供基本的Qt功能。如果在代码执行过程中找不到qt5core.dll,可能导致相关功能无法正常使用。以下是五种详细解决方法、qt5core.dll文件详细介绍以及丢失原因。 一、qt5core.dll文件详细介绍 文件名称:q…

白杨SEO:从董宇辉事件聊聊个人IP这个事,企业为什么要重视个人IP?

董宇辉事件是指东方甄选因主播董宇辉的小作文到底由谁写的风波,具体详情可以网上搜搜,最近是热搜。下图1产生原因,下图2董宇辉回应截图。 白杨SEO说一下,这里不关注谁对谁错。我想说的是,一是现在个人IP非常重要&…

《微信小程序开发从入门到实战》学习五十一

4.5 实现投票小程序服务端功能 4.5.4 获取我的投票信息 最后实现“我的”投票页面。该页面pages/myVote/myVote.js还有一个todo,获取用参与的所有投票的列表。这个功能需要用到用户的openid,因此也需要使用云函数来实现。 新建myVoteList云函数。完成代码将其上传…

C语言结构体小项目之通讯录代码实现+代码分析

一、思路 1.文件 这里由于通讯录实现代码较长,因此分三个文件进行,contact.c用于实现通讯录主体代码,声明各项头文件用contact.h实现,测试用test.c 二.功能 增加联系人删除联系人修改联系人查找指定联系人排序显示通讯录的信息…

Mac 打不开github解决方案

序言 github 时有打不开的情况,为此很是烦恼,这里分享一下如何解决这种问题,其实问题的本质是在访问github网页时无法通过github.com的二级域名进行动态域名解析。 解决方案 手动配置静态文件hosts,将该域名和IP的映射关系添加…

vue文件下载请求blob文件流token失效的问题

页面停留很久token失效没有刷新页面,这时候点击下载依然可以导出文件,但是文件打不开且接口实际上返回的是401,这是因为文件下载的方式通过window创建a标签的形式打开的,并没有判断token失效问题 const res await this.$axios.…

10:00面试,10:08就出来了,问的问题超出我认知

本来在上家公司上班,加班是每天必不可少的,但是看在加班费给的比较多的份上,就没有太计较了。没想到9月份下一份通知,所有人不准加班,加班费不仅没有了,薪资还要降30%,这下搞的生活都生活不下去了。 还好有…

Dijkstra求最短路 I(Dijkstra算法)

给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环,所有边权均为正值。 请你求出 1 号点到 n 号点的最短距离,如果无法从 1 号点走到 n 号点,则输出 −1。 输入格式 第一行包含整数 n 和 m。 接下来 m 行每行包含三个整…

vscode 常用 Emmet Abbreviation 快捷方式

vscode 常用 Emmet Abbreviation 快捷方式 输入快捷指令后&#xff0c; 按“tab”键或者回车键 即可 .box*5&#xff1a;生成 5 个 class 为 box 的 div 元素 <div class"box"></div> <div class"box"></div> <div class&quo…

python和pygame实现捉小兔游戏

python和pygame实现捉小兔游戏 python和pygame实现捉小兔游戏&#xff0c;需要安装使用第三方库pygame&#xff0c;关于Python中pygame游戏模块的安装使用可见 https://blog.csdn.net/cnds123/article/details/119514520 下面是使用Python和Pygame创建的游戏&#xff0c;其中有…

常用的Linux基本命令

这些是一些常用的Linux基本命令&#xff0c;涵盖了文件操作、系统管理、进程管理、磁盘管理等方面&#xff1a; ls&#xff1a;列出目录内容cd&#xff1a;切换当前工作目录pwd&#xff1a;显示当前工作目录的绝对路径mkdir&#xff1a;创建新目录rmdir&#xff1a;删除空目录…

Pytorch从零开始实战13

Pytorch从零开始实战——ResNet与DenseNet探索 本系列来源于365天深度学习训练营 原作者K同学 文章目录 Pytorch从零开始实战——ResNet与DenseNet探索环境准备数据集模型选择开始训练可视化总结 环境准备 本文基于Jupyter notebook&#xff0c;使用Python3.8&#xff0c;P…