Linux基于CentOS学习【进程状态】【进程优先级】【调度与切换】【进程挂起】【进程饥饿】

目录

进程状态

状态决定了什么

进程等待方式——队列

 进程状态的表现

挂起状态

基于阻塞的挂起——阻塞挂起

swap分区

进程状态表示

Z僵尸状态

进程的优先级

什么是进程的优先级

为什么会有进程的优先级

进程饥饿

Linux的调度与切换

切换

调度

queue [ 140 ]:优先级

bitmap [ 5 ]  :解决效率

*active & *expried:解决饥饿问题

阻塞和等待CPU运行


进程状态

状态决定了什么

状态决定了后续动作,如果是运行状态,那么后续就意味着可以随时被调度运行,如果是阻塞状态那么意味着要等待某种资源

阻塞状态举例:在编写代码的时候,我们会经常写scanf 或者是cin 当运行时,计算机就会在那里等待我们的输入,此刻就是阻塞状态的最好体现,它就是在等待一种资源,它将进程卡在那里,不会被CPU执行,主要是当前要等待键盘资源就绪,等待数据输入进去。它会将这个程序的PCB从运行状态改为阻塞状态,并且将其从运行队列中拿下来,放到等待队列中去

为什么CPU不往后执行呢?因为当前代码没有将scanf 或者 cin执行完,程序无法执行下去

进程等待方式——队列

不仅仅是CPU有队列,我们底层对应的网络设备或者一般的IO设备等,都有自己的队列

所以,当我们对这些设备进行访问的时候

1,OS根据描述的硬件数据结构的对象,以及对象的状态,亦或是通过一些数字,我们可以得知底层的设备的一些状态

2,  我们对应的每种硬件状态所对应的描述结构体,可以帮助我们找到该设备等待的进程,方便我们随时唤醒

3,OS作为硬件的管理者,对硬件当前的状态是非常清楚的,一旦硬件准备就绪,OS会将等待该资源的进程重新唤醒,所谓的唤醒,本质上就是将阻塞状态改为运行状态,并且投入到运行队列里。

让进程状态变更,本质上就是把进程放到不同的队列里

 进程状态的表现

所谓进程状态,本质就是一个整型变量,就是task_struct中的一个整型变量,它表示状态的值

比如,通过返回不同的整型来反映它是啥状态的

#define New 1
#define ready 2
#define running 3
#define block 4struct task_struct
{...int status;   ...
}

一个CPU维护一个运行队列,主要在运行队列里,它的状态都可以被称为运行状态

硬件的就绪状态只有OS最清楚,因为OS是硬件的管理者

当我们的进程在等待软硬件资源的时候,资源如果没有准备就绪,我们的task_struct只能

1,将自己设置为阻塞状态

2,将自己的PCB链入等待队列

状态的变迁引起的是PCB被OS搬到不同的队列里


挂起状态

基于阻塞的挂起——阻塞挂起

把进程的管理转换为对某种数据结构的增删查改,每一个进程都有匹配的代码和数据

如果当前等待的外设在短期之内不会就绪,那么它就会在阻塞状态里进行等待,但当OS压力特别大,整机或者CPU,内存所对应的剩余资源变得越来越少,那么资源现在严重不足了,不能够分配,对于计算机讲,将面临着大量的操作失败,就不能向上提供良好的运行环境,比如打游戏直接卡成PPT

对于OS,要么直接崩溃,要么需要想办法挤压资源,OS需要对整个系统内进行重新安排,阻塞进程就是浪费的其中一部分,阻塞进程一又还没有等到资源,二又站着OS分配的管理资源,本来我就资源紧张了,你等待队列里还占着那么多不干活的task_struct

所以在资源紧张的时候,会将task_struct对于的代码和数据换出,但是不会将task_struct换出,换出了就管理不了了,如果你将task_struct都赶出去了,谁还知道你有这个进程

进程 = 内核PCB对象 + 可执行程序(代码和数据) 

swap分区

磁盘有一个固定区域,是专门供给当OS资源紧张的时候,OS能够将一些不是特别紧要的资源进行换入和换出,即swap分区

当OS压力最大的时候,就会将一些文件啊,进程啊,代码数据啊,传到磁盘的swap区,这个工作叫换出

等到顶住了这波压力,且想调度了的时候,我们就将swap区的资源换回来,这个工作就叫做换入

所以当我们的进程它所对应的代码和数据不在内存中的时候,此时就称该进程为挂起状态,这种叫做阻塞挂起

创建进程时,实现创建PCB呢,还是先加载代码和数据到内存呢?

答案是先创建内核数据结构PCB,也就是先把管理字段创建出来,OS才知道你有这个进程,数据代码还可以晚点换入

swap分区一般不会特别大,因为我们整体的换出,本质是个把数据拷贝到外设的过程,换入本质是将数据拷贝到内存里。如果太大的话,会加深内存与磁盘的频率,从而引发IO的频率升高,无效操作就会变多

进程状态表示

static const char * const task_state_array[] = {"R (running)", /* 0 */"S (sleeping)", /* 1 */"D (disk sleep)", /* 2 */"T (stopped)", /* 4 */"t (tracing stop)", /* 8 */"X (dead)", /* 16 */"Z (zombie)", /* 32 */
}; 
R 运行状态( running : 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里, 后面的+表示是前台

S状态可称为阻塞状态,也可称为可中断睡眠,浅度睡眠

D状态可称为不可中断睡眠,深度睡眠

操作系统杀不死D状态的进程,但是S状态可以被杀,但是一旦出现系统级别的D状态,也说明系统已经很紧要了

D状态也是阻塞状态

T状态,暂停状态

kill -l 查看信号

其中,9号信号就是平常所使用的杀进程信号

19号信号是让这个进程暂停

 再查看一下

一般我们的进程会在什么时候处在暂停状态呢

进程读取某一设备时,但是设备又不允许给你读,OS又不好杀掉,就让其处于暂停状态

恢复暂停状态,18号信号,就是恢复

恢复之后 ,CTRL+c是杀不掉的,因为在暂停的时候,进程就转移到后台了,恢复了也还是后台,只能用信号9来杀掉 

t状态,也是属于等待某种资源

暂停状态可不可以也认为是阻塞状态?

可以,因为都是在等待某种资源

Z僵尸状态

我们在执行完一个进程的时候,对于进程里所对应的代码和数据,可以直接被释放,但是进程所对应的PCB不应该立即就被释放掉,这样做是因为为了系统或者其它进程能够读取到子进程或者这个进程的退出数据。

只有将这些数据拿走后,才是真正的死亡状态,才能释放PCB

我们将一个进程执行完毕,但是并没有获取进程退出的相关数据,此时就叫做Z状态

一个父子进程,如果子进程退了,那么父进程就一定要去读取子进程的状态,如果不读取,此时子进程的PCB就不释放,此刻就是Z状态        

  1 #include<stdio.h>2 #include<unistd.h>3 #include<stdlib.h>4 int main(){5   pid_t id = fork();6   if(id == 0){7     //child8     int cnt = 5;9     while(cnt){10       printf("I am child, pid :%d ,ppid : %d\n",getpid(),getppid());11       sleep(1);12       cnt--;                                                                             13     }14     exit(0);    //让子进程直接退出15   }16 17   //father18   while(1){19     printf("I am father, pid :%d ,ppid : %d\n",getpid(),getppid());20     sleep(1);21   }}

Q:为什么要有Z状态?

A:创建进程是希望这个进程给用户完成工作的,子进程必须要有结果数据,这些在PCB中

Q:什么是Z:

A:进程已经退出,但是当前的进程状态需要自己维持住,供上层读取,就必须处于Z状态

Q:如果我作为父进程不读取呢?

A:就会带来这个僵尸状态的进程一直存在,task_struct对象就要一直存在,这些就要占据内存空间,一直不释放最终导致的问题就是内存泄漏

所以所有的进程在退出的时候,都必须先处于Z状态,被人状态读取完后才会变成X,最后完全退出

Q:        父进程比子进程先挂,子进程变成僵尸的时候会由谁来收?

A:        不会出现这种情况,如果父进程先挂掉的话,其子进程就会被1号进程所领养,1号进程就是操作系统领养进程就会被称为孤儿进程,但是孤儿进程可以有子进程的

进程的优先级

什么是进程的优先级

进程要访问某种资源,进程进行通过一定的方式,比如排队,来确认享受资源的先后顺序

优先级和权限的区别:权限决定的是能不能做的问题,而优先级决定的是谁先的问题

为什么会有进程的优先级

资源过少带来的,但是资源过少是属于一个相对概念,每一个进程都要有它的运行队列,CPU又只有一个,所以谁先跑要排队

Linux的默认优先级是80,优先级可以修改,优先级的范围是 [60,99],总共40个

数字越小,优先级越高!但不建议调整优先级

Linux系统允许用户调整优先级,但是不能直接让你修改PRI,而是修改nice值,nice值不是优先值,而是进程优先值的修正数据 !

pri = pri(old) + nice;

pri (old)每次都是从80开始,在Linux的内核里,它会做判断,如果你的nice值超过系统给它设置的最大值,比如我突然100上去,它也不会取100,而是取19,从而到达99,反之nice值的最小值是20,不会说你取-100,就给你干到-20去

进程饥饿

为什么Linux的优先级的调整是会受到限制?

不加限制的话,就会将自己的进程优先级调整得非常高,别人的优先级就会调成非常低

优先级较高的进程,优先得到资源,其后又会源源不断地产生新的进程,最后导致的结果就是常规进程很难享受到优先级的资源,从而导致进程饥饿问题

好比你正常排队,却老是有人插队,最终饿的却是正常人

所以操作系统一般都会有分时操作系统,调度上,它能够较为公平的进行调度,且会对调度范围进行严格的限制

Linux的调度与切换

Q:进程在运行的时候,放在CPU上,是直接必须把进程代码跑完才行吗?

A:答案是明显不行的,比如是死循环,操作系统是绝对不允许让死循环一直跑下去的

现代操作系统,都是基于时间片进行轮换执行的,防止恶性竞争

竞争性 : 系统进程数目众多,而CPU 资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高 效完成任务,更合理竞争相关资源,便具有了优先级
独立性 : 多进程运行,需要独享各种资源,多进程运行期间互不干扰
并行 : 多个进程在多个 CPU 下分别,同时进行运行,这称之为并行
并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发,非常非常非常高频

CPU里面有大量的寄存器,eip寄存器里保存最经典的就是PC指针 

当一个进程在CPU上运行时,CPU上的所有寄存器就要围绕着这个进程来进行展开运算,换句话说,这个进程在CPU运行期间,进程会在CPU内部形成大量的临时数据,这些临时数据放在CPU的寄存器中

切换

所有的保存都是为了恢复,所有的恢复都是为了上一次的运行

进程在CPU的各种数据,当时间片到了,需要我们的进程进行切换的时候我,我们首先要做的就是将CPU上运行的数据进行保存,保存的地点就是该进程的PCB里,一般就是存储在PCB里的tss_struct的结构里

CPU内部的所有临时数据,我们叫做进程的硬件上下文

进程进行保护硬件上下文的工作称为保护上下文

当进程被二次调度的时候(这里的二次调度并不是说被调了两次,而是可以指两次,三次,多次),我们的进程被放到CPU上运行的时候,首先要做的就是,要将曾经保存的硬件上下文进行恢复

所以进程进行切换工作的时候,一定会做的两个工作

一个就是保护前者的硬件上下文,第二个就是恢复后者的硬件上下文

CPU内的寄存器只有一套,寄存器内部保存的数据可以有多套

那我们区分一下,寄存器和寄存器内容

虽然寄存器的数据放在了一个共享的CPU设备里面,但是所有的数据其实都是被进程私有的,CPU内的任意时刻的数据都只是属于某一进程

寄存器不等于寄存器的内容!!!

调度

Linux实现进程调度的算法,要考虑优先级,考虑饥饿,考虑效率

queue [ 140 ]:优先级

在runqueue(运行队列)里,我们有两个queue[140],它们都是属于数组指针,为什么是140呢?

它的0~99是不使用的,只用100~139

接下来需要配合的就是Linux的默认优先级是80,优先级可以修改,优先级的范围是 [60,99],总共40个

好比如果你的优先级是60,它会根据Linux的调度算法,进行运算,将你放到 [ 100 ] 位置上,所以在一定程度上,这个队列可以映射优先级的先后顺序

每次运行之前,其会对着140进行遍历,为空则下一个,不为NULL则运行这个队列的优先级队列

我们可以看出,我们运行队列有140个,但真正需要检测的只有40个,难道我们每次都要多检测100个吗,显然不是的,我们会用到runqueue结构中的另一个数组,bitmap[ 5 ]

bitmap [ 5 ]  :解决效率

bitmap 是int 类型的,总共有5个单位,共5*32 = 160个比特位,其每个比特位有各自的含义

比特位的位置表示哪一个队列,比特位的内容表示队列是否为空,我有160个比特位,而运行队列只有140个单元,比特位比它还多20个,我那20个就不用了,其中有队列的位置,比特位标1,没有队列的位置,比特位标0

如此,就转换为了检测比特位就可,因为位操作会比遍历操作快得多

检查二进制中有多少个1

调度算法时间复杂度为O(1)

优先级解决了,效率解决了,那我饥饿问题咋办

也就是说,每次我都把我的优先级调成60,并放入到queue[140]队列的最前端,那我后面的进程岂不是要一直饿着?

解决办法就是:优先级数组不只是只有一个,其实还有一个,前面的那个queue [140] 是活跃队列,另一个叫做过期队列,两个数组互不干扰,CPU调度进程调度的是活跃队列,OS存放进程存放的是过期队列,即便来了优先级更高的进程,其也只会在过期队列里等待

活跃队列queue[140] + bitmap[5] + nr_active  构成一个结构体

过期队列queue[140] + bitmap[5] + nr_active  构成一个结构体

struct q {nr_active;bitmap[5];queue[140];
}

两个结构体可以构成结构体数组

struct q array[2];

*active & *expried:解决饥饿问题

这是两个指针,刚开始struct q *active = &array[0] , struct q *expried = &array[1]

当array[0] 中的queue[140] 不断减少,直至为0的时候,且array[1] 里的内容不断增多的时候

就执行swap ( &active , &expried ) ,交换的时候,更改的是指针变量的内容

阻塞和等待CPU运行

这时候就会问,在运行队列中等待被调度的过程算不算等待资源,既然是等待资源的话,会不会就是阻塞状态,这样做不会矛盾吗

运行队列(runqueue)中的进程处于可运行状态,这意味着它们已经准备好被CPU执行,并且正在等待获取CPU资源。这些进程并不是在等待特定的资源,如I/O操作或页面置换等,而是在等待CPU时间。

当进程处于运行状态(TASK_RUNNING)时,它们在运行队列中,这意味着它们已经准备好运行,并且内核调度器将决定哪个进程将获得CPU时间。这些进程不是在等待资源,而是在等待CPU时间来执行。

如果一个进程需要等待某个资源(如磁盘I/O、网络响应或锁),它通常会被放置在等待队列(wait queue)中,而不是运行队列。等待队列是与特定资源或条件相关的队列,当资源变得可用或条件得到满足时,进程会被唤醒并可能被放入运行队列。

因此,运行队列中的进程是在等待CPU资源,而不是在等待其他类型的资源。 

以上就是本博文的学习内容,如果有不正确的地方,还望各位大佬指点出来,谢谢阅读! 

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

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

相关文章

使用本地模型根据对话对客户进行画像

基于ollama部署本地模型&#xff0c;如&#xff1a;qwen2.5。通过迭代提示词实现客户画像的生成&#xff0c;根据具体需求&#xff0c;通过迭代提示词可以达成目标。输出的结果可以要求JSON格式输出&#xff0c;当前模型JSON的解析准确率比较高&#xff0c;在输出的content中&a…

【可视化大屏】将柱状图引入到html页面中

到这里还是用的死数据&#xff0c;先将柱状图引入html页面测试一下 根据上一步echarts的使用步骤&#xff0c;引入echarts.js后需要初始化一个实例对象&#xff0c;所以新建一个index.js文件来进行创建实例化对象和配置数据信息等。 //在index.html引入<script src"j…

案例分享—国外优秀UI设计作品赏析

国外深色界面UI设计的简洁感首先来源于其对色彩运用的精妙。深色背景能有效减少视觉干扰&#xff0c;使关键元素如文字、图标等更加突出。这种设计不仅提升了信息的可读性&#xff0c;还让界面显得更为简洁、清晰&#xff0c;用户能够更快地找到所需信息&#xff0c;提升使用体…

Linux,中文输入法、C/C++编译环境配置

一、Linux中文输入配置 1、点击设置中的区域与语言 2、此处无声胜有声 一定要选第一个汉语&#xff08; Intelligent pingying&#xff09;,要不然最后打不出来中文字 二、VScode C/C环境配置 先下载插件&#xff0c;中文插件和C/C环境插件 终端依次执行下列命令行&#xff0…

【自动驾驶汽车通讯协议】GMSL通信技术以及加串器(Serializer)解串器(Deserializer)介绍

文章目录 0. 前言1. GMSL技术概述2. 为什么需要SerDes&#xff1f;3. GMSL技术特点4.自动驾驶汽车中的应用5. 结论 0. 前言 按照国际惯例&#xff0c;首先声明&#xff1a;本文只是我自己学习的理解&#xff0c;虽然参考了他人的宝贵见解及成果&#xff0c;但是内容可能存在不准…

3D看车如何实现?有哪些功能特点和优势?

3D看车是一种创新的汽车展示方式&#xff0c;它利用三维建模和虚拟现实技术&#xff0c;将汽车以更真实、更立体的形式呈现在消费者面前。 一、3D看车的实现方式 1、三维建模&#xff1a; 通过三维建模技术&#xff0c;按照1:1的比例还原汽车外观&#xff0c;包括车身线条、细…

C语言 | Leetcode C语言题解之第452题用最少数量的箭引爆气球

题目&#xff1a; 题解&#xff1a; int cmp(void* _a, void* _b) {int *a *(int**)_a, *b *(int**)_b;return a[1] < b[1] ? -1 : 1; }int findMinArrowShots(int** points, int pointsSize, int* pointsColSize) {if (!pointsSize) {return 0;}qsort(points, pointsSi…

七氟烷麻醉药市场研究:未来几年年复合增长率CAGR为4.2%

七氟烷是一种吸入麻醉剂&#xff0c;用于在外科手术过程中诱导和维持全身麻醉。七氟烷是一种挥发性麻醉剂&#xff0c;常用于在外科手术过程中诱导和维持全身麻醉。它因起效快和作用消失快而受到青睐&#xff0c;是成人和儿科患者的理想选择。七氟烷通常通过吸入起作用&#xf…

linux-冯诺伊曼体系结构以及操作系统

冯诺依曼体系结构 我们不畅见到计算机&#xff0c;如笔记本&#xff0c;不常见的如服务器&#xff0c;大部分都遵循着冯诺伊曼体系结构 截至目前&#xff0c;我们所认识的计算机&#xff0c;都是由一个个硬件组件组成。 输入单元&#xff1a;包括键盘 , 鼠标&#xff0c;扫描…

文件防泄密措施措施有哪些?5种文件防泄密措施等你体验!【小白成长篇!】

“千里之堤&#xff0c;溃于蚁穴。” 这句谚语告诉我们&#xff0c;再坚固的防线也可能因为一个小小的疏忽而崩溃。 在信息安全领域&#xff0c;文件泄密同样如此。 一个小小的失误&#xff0c;就可能导致企业的核心机密外泄&#xff0c;造成无法挽回的损失。 因此&#xff…

人脸表情行为识别系统源码分享

人脸表情行为识别系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Vis…

初入网络学习第一篇

引言 不磨磨唧唧&#xff0c;跟着学就好了&#xff0c;这个是我个人整理的学习内容梳理&#xff0c;学完百分百有收获。 1、使用的网络平台:eNSP 下载方法以及内容参考这篇文章 华为 eNSP 模拟器安装教程&#xff08;内含下载地址&#xff09;_ensp下载-CSDN博客https://b…

15分钟学 Python 第37天 :Python 爬虫入门(三)

Day 37 : Python爬虫入门大纲 章节1&#xff1a;Python爬虫概述 1.1 什么是爬虫&#xff1f; 网页爬虫&#xff08;Web Crawler&#xff09;是一种自动访问互联网上网页并提取数据的程序。爬虫的作用包括搜索引擎索引内容、市场调查、数据分析等。 1.2 爬虫的工作原理 发起…

计算机毕业设计 基于Django的在线考试系统的设计与实现 Python+Django+Vue 前后端分离 附源码 讲解 文档

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

考研报名记录冲冲冲

研究生报名 网址 https://yz.chsi.com.cn/apply/ 报名包括网上报名和网上确认两个阶段&#xff0c;所有考生均须在规定时间内参加网上报名和网上确认。网上报名时间为2024年10月15日至10月28日&#xff08;网上预报名时间为2024年10月9日至10月12日&#xff0c;网上预报名和正…

Golang | Leetcode Golang题解之第455题分发饼干

题目&#xff1a; 题解&#xff1a; func findContentChildren(g []int, s []int) (ans int) {sort.Ints(g)sort.Ints(s)m, n : len(g), len(s)for i, j : 0, 0; i < m && j < n; i {for j < n && g[i] > s[j] {j}if j < n {ansj}}return }

Figma:现代设计工具使用指南

Figma&#xff1a;现代设计工具使用指南 在当今数字设计的世界中&#xff0c;Figma 已经成为设计师、开发者和团队协作的重要工具。作为一款基于云的设计平台&#xff0c;Figma 不仅支持界面设计和原型制作&#xff0c;还提供强大的协作功能。本文将详细介绍 Figma 的主要功能、…

aws(学习笔记第一课) AWS CLI,创建ec2 server以及drawio进行aws画图

aws(学习笔记第一课) 使用AWS CLI 学习内容&#xff1a; 使用AWS CLI配置密钥对创建ec2 server使用drawio&#xff08;vscode插件&#xff09;进行AWS的画图 1. 使用AWS CLI 注册AWS账号 AWS是通用的云计算平台&#xff0c;可以提供ec2&#xff0c;vpc&#xff0c;SNS以及clo…

图文深入理解Oracle DB Scheduler

值此国庆佳节&#xff0c;深宅家中&#xff0c;闲来无事&#xff0c;就多写几篇博文。今天继续宅继续写。本篇图文深入介绍Oracle DB Scheduler。 Oracle为什么要使Scheduler&#xff1f; 答案就是6个字&#xff1a;简化管理任务。 • Scheduler&#xff08;调度程序&#x…

【Python】如何让SQL Server像MySQL一样拥有慢查询日志(Slow Query Log慢日志)

如何让SQL Server像MySQL一样拥有慢查询日志&#xff08;Slow Query Log慢日志&#xff09; SQL Server一直以来被人诟病的一个问题是缺少了像MySQL的慢日志功能&#xff0c;程序员和运维无法知道数据库过去历史的慢查询语句。 因为SQLServer默认是不捕获过去历史的长时间阻塞…