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

news2024/11/26 19:55:28

目录

进程状态

状态决定了什么

进程等待方式——队列

 进程状态的表现

挂起状态

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

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 4


struct 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     //child
  8     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   //father
 18   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.coloradmin.cn/o/2190140.html

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

相关文章

模拟算法(3)_Z字形变换

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 模拟算法(3)_Z字形变换 收录于专栏【经典算法练习】 本专栏旨在分享学习算法的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 1. 题目链…

VGG原理与实战

VGG网络结构 这也更好的块状结构,256个卷积核 卷积就是我们的一个特征图啊往往都会缩小 &#xff0c;然后的话但它通道不会变.卷积一般是使用我们的通道C变大,磁化但是它的通道就是我们那个H和W一般都会变小.下采样的意思就是使分辨率变小 vgg—block内的卷积层都是同结构的意…

【杂谈二之Relay继电器】介绍Relay继电器的概念、原理、分类以及实例应用

一、Relay是什么 Relay就是一个电控制的开关 二、Relay的工作原理 宏观上看主要由两部分电路组成&#xff0c;左侧的电路是低电流电路&#xff0c;右侧是高电流电路 左侧是由线圈绕制成&#xff0c;当有电流通过时就会产生磁场&#xff0c;会对于电枢产生吸引&#xff0c;由于…

【cpp/c++ summary 工具】 vcpkg 包管理器

由于之前的Hunter 包管理器在Boost的构建中速度太慢&#xff0c;准备尝试一下vcpkg。 vcpkg是由microsoft开发的、适用于 Windows、Linux 和 MacOS 的 C 库管理器。 1. 安装 vcpkg&#xff1a; 普通安装 C:\windows\system32>git clone https://github.com/microsoft/vcp…

华为 HCIP-Datacom H12-821 题库 (32)

&#x1f423;博客最下方微信公众号回复题库,领取题库和教学资源 &#x1f424;诚挚欢迎IT交流有兴趣的公众号回复交流群 &#x1f998;公众号会持续更新网络小知识&#x1f63c; 1.当一个运行 MSTP 协议的交换设备端口收到一个配置BPDU 时&#xff0c;会与设备保存的全局配…

20241005给荣品RD-RK3588-AHD开发板刷Rockchip原厂的Android12时使用iperf3测网速

20241005给荣品RD-RK3588-AHD开发板刷Rockchip原厂的Android12时使用iperf3测网速 2024/10/5 14:06 对于荣品RD-RK3588-AHD开发板&#xff0c;eth1位置上的PCIE转RJ458的以太网卡是默认好用的&#xff01; PCIE TO RJ45&#xff1a;RTL8111HS 被识别成为eth0了。inet addr:192.…

华为OD机试 - 最大连续文件之和(Python/JS/C/C++ 2024 E卷 200分)

华为OD机试 2024E卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试真题&#xff08;Python/JS/C/C&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;私信哪吒&#xff0c;备注华为OD&#xff0c;加入华为OD刷题交流群&#xff0c;…

1.资源《Arduino UNO R3 proteus 仿真工程》说明。

资源链接&#xff1a; Arduino UNO R3 proteus 仿真工程 1.文件明细&#xff1a; 2.文件内容说明 包含&#xff1a;proteus工程、原理图、仿真程序。 3.内容展示 4.简述 该文件为proteus工程&#xff0c;用于Arduino uno r3仿真。 因为软件自动运行&#xff0c;所以最小…

深度学习每周学习总结J1(ResNet-50算法实战与解析 - 鸟类识别)

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制 目录 0. 总结1. 设置GPU2. 导入数据及处理部分3. 划分数据集4. 模型构建部分5. 设置超参数&#xff1a;定义损失函数&#xff0c;学习率&a…

c++结构体嵌套

没有很听懂这个课 有点乱了、 // // Created by 徐昌真 on 2024/10/5. // #include <iostream> using namespace std; int main() {struct Point{ //定义一个叫做point的结构体double x, y;};struct Radius{Point pt; //嵌套point结构体在radius结构体里面 把他名字定…

网络威胁情报技术的进步

网络威胁形势不断演变&#xff0c;必然导致防御者和攻击者之间持续展开军备竞赛。幸运的是&#xff0c;网络威胁情报 (CTI) 技术的进步为安全专业人员提供了强大的工具&#xff0c;使他们能够保持领先地位。 本指南深入探讨了 CTI 的最新进展&#xff0c;让您了解这些技术如何…

设计模式之桥接模式(Bridge)

一、桥接模式介绍 桥接模式(bridge pattern) 的定义是&#xff1a;将抽象部分与它的实现部分分离&#xff0c;使它们都可以独立 地变化。 桥接模式用一种巧妙的方式处理多层继承存在的问题&#xff0c;用抽象关联来取代传统的多层继承&#xff0c; 将类之间的静态继承关系转变为…

【CKA】十四、监控pod的日志

14、监控pod的日志 1. 考题内容&#xff1a; 2. 答题思路&#xff1a; 查看名字是foobar的pod的日志&#xff0c;过滤出 unable-to-access-website&#xff0c;导入到文件中就可以&#xff0c;这道题还是挺简单的 3. 官网地址&#xff1a; https://kubernetes.io/zh-cn/doc…

dll动态库加载失败导致程序启动报错以及dll库加载失败的常见原因分析与总结

目录 1、问题说明 2、dll库的隐式加载与动态加载 2.1、dll库的隐式加载 2.2、dll库的显式加载 3、使用Process Explorer查看进程加载的dll库信息以及动态加载的dll库有没有加载成功 3.1、使用Process Explorer查看进程加载的dll库信息 3.2、使用Process Explorer查看动态…

警惕!脑出血前这8大预警信号,你不可不知!

在这个快节奏的时代&#xff0c;健康成为了我们最宝贵的财富之一。然而&#xff0c;突如其来的疾病往往让人措手不及&#xff0c;尤其是像脑出血这样的严重疾病&#xff0c;其发病急、进展快&#xff0c;若不及时识别并就医&#xff0c;后果不堪设想。今天&#xff0c;我们就来…

在登陆功能中添加Redis缓存

目录 基于Redis实现短信登录 实现流程图 实现代码 解决登录状态刷新问题 初始方案思路&#xff1a; 实现代码 发送验证码 登陆实现 如果是新用户则自动创建 运行测试 基于Redis实现短信登录 实现流程图 实现代码 Overridepublic Result login(LoginFormDTO loginForm…

影刀RPA:Excel内容填充指令

1.实战目标 本次主要介绍影刀RPA如何操作内容相关的填充与替换指令。主要包含以下 这些指令在数据处理方面有着重要的作用&#xff0c;可以对数据做运算&#xff0c;填充&#xff0c;替换&#xff0c;实现数据格式统一&#xff0c;便于最终的数据分析。在操作的过程中&#xf…

WordPress修改固定链接后301的重定向方法

网站改版实际上是很忌讳的&#xff0c;尤其是针对已被搜索引擎收录的网站&#xff0c;新站不用考虑这些问题&#xff0c;而已经收录的网站网页在不遵守搜索引擎规则的前提下&#xff0c;是会被降权&#xff0c;关键词排名下滑、流量IP会被剥夺、收录会减少 、业务成交量会急剧下…

(Linux驱动学习 - 6).Linux中断

一. Linux 中断 API 函数 1.中断号 每个中断都有一个中断号&#xff0c;通过中断号即可区分不同的中断&#xff0c;有的资料也把中断号叫做中 断线。在 Linux 内核中使用一个 int 变量表示中断号。 2.申请中断 - request_irq 函数原型&#xff1a; int request_irq(unsigne…

【ubuntu】APT、apt、apt-get介绍

目录 1.APT简介 2.常用apt指令 2.1安装 2.2更新列表 2.3更新已经安装的软件包 2.4搜索软件包 2.5显示软件包信息 2.6移除软件包 2.7清理无用的安装包 2.8清理无用的依赖项 3.apt和apt-get 3.1区别 3.2 总结 1.APT简介 APT的全称是advanced package …