初识进程状态

🌎进程状态【上】


文章目录:

进程状态

    发现进程的状态

    运行队列

    进程排队

    进程状态的表述
      状态在代码中的表示
      运行状态
      阻塞状态
      挂起状态

    总结


前言:

  为了搞明白正在运行的进程是什么意思,我们有必要了解进程的不同状态,那么话不多说,开始我们今天的话题!

在这里插入图片描述


🚀发现进程的状态

  我们按照上次所说的创建子进程,分别执行不同的工作:

  1 #include<stdio.h>2 #include<stdlib.h>3 #include<unistd.h>4 #include<sys/types.h>5 6 int main()7 {8     printf("before fork!\n");9     sleep(3);10     printf("start fork!\n");11     sleep(1);12 13     pid_t id = fork();14     if(id < 0)15     {16         perror("fork error!\n");17         exit(0);18     }19 20     if(id == 0)//子进程21     {22         int cnt = 6;23         while(cnt)24         {25             printf("I'm child process, pid=%d\n", getpid());26             sleep(1);27             cnt--;                                                                                                                                                                                                                                                                                                                                                                        28         }29         exit(0);30     }31 	//父进程32     sleep(1);33     int cnt = 5;34     while(cnt)35     {36         printf("I'm father process, pid=%d\n", getpid());37         sleep(1);38         cnt--;39     }40 41     return 0;42 }
~

  这里使用了 exit() 函数,我们以前可能在C语言里见到过它,只知道它可以退出程序。其实在Linux当中exit函数是 退出进程 接口:

在这里插入图片描述

  它的作用是终止一个进程,而函数参数是 退出码(这个以后会谈),表示 退出状态

  那我们把程序运行起来之后,再使用监控脚本进行监控:

在这里插入图片描述
  观察我们从监控脚本得出的结果,我们发现带有 STAT 的一栏里除了最后一项我标红的位置为 “Z” 外,其他的状态都是 “S+” 状态,并且在标红的这一行,的最后,出现了 <defunct> 的字样。

  这个就是我们今天要说的——进程状态


🚀运行队列

  进程的状态,一定是与CPU如何执行有关的,所以在了解进程状态之前,有必要先了解CPU如何执行进程。

  我们说过,程序运行起来时就是一个进程,进程需要被CPU给执行,并且进程是以 循环队列 的形式被CPU执行,但是进程在CPU上并不是一直在执行的。

在这里插入图片描述

  每一个进程都有自己的 时间片 ,也就是 每个进程运行最大时间超过这个时间如果程序还没有被执行完毕,则强制退出,执行下一个进程,这个进程则重新排队等待CPU资源。

  当然,有些情况下进程也许是在等待某些硬件资源,所以并不会一直执行,比如:

#include<stdio.h>int main()
{int ind = 0;scanf("%d", &ind);printf("%d", ind);return 0;
}

在这里插入图片描述
  这个时候,程序此时就在等待我们硬件资源,也就是键盘的写入。

  我们知道,进程 = task_struct + 可执行程序 ,那我们进程在排队的时候是 task_struct 在排队,还是可执行程序在排队,亦或是两者都排队呢?我们不妨讲个故事:

  有一天,阿熊自信满满,觉得自己实力已经可以去闯闯了,于是阿熊连夜写了一份简历,第二天就向自己心仪的公司投递了过去,每天期待着答复。
  这天,面试官手里拿着10份简历,按照面试官对应聘者的评价依次排放,筛选出自一半交给了hr,很幸运,阿熊居然没被刷下来,hr按照这个顺序依次比较,最后hr看着阿熊的简历坦然一笑…[未完]

  其实,阿熊可以看为进程的代码和数据,而简历可以看作进程的PCB,而阿熊的简历被hr拿到的简历在一起的时候,其实就是进程排队的过程。

  所以我们可以得出 结论进程排队不是进程的可执行程序在排队,而是进程的PCB在排队!

  于是就在当天晚上,阿熊收到了一封短信:“尊敬的阿熊,介于您出色的表现,已经进入我司人才库…” 然而就在阿熊一个人偷抹眼泪的时候,某个面试官正在骂骂咧咧投递自己的简历到另一家公司…[结束]


🚀进程排队

  那么如何理解进程排队这件事情,进程排队本质上就是数据结构的双向链表,但是稍稍不同的是,这个指针指向的并不是下一个PCB的开始,而是PCB内部的一个指针。

在这里插入图片描述
  那么如何通过PCB的中间链表去访问链表以上的属性信息呢?其实很简单:

struct task_struct
{char ch1;char ch2;char ch3;
}

  假如我们要从 ch3 访问 ch1,只需要ch3 - 2,也就是根据ch3到ch1的 偏移量 来确定ch1的位置,同样,在PCB的内部也是根据偏移量来确定位置的

  那么在我们Linux内核中是如何确定偏移量的呢?

在这里插入图片描述

  话说回来,进程排队的意义是什么?我们应该已经清楚了:只要是在排队,就一定是在等待某种资源!


🚀进程状态的表述

✈️状态在代码中的表示

  我们都知道,Linux是使用C语言写的,而如何描述进程状态,其实就是使用 来表示对应的状态,比如:

#define NEW 0
#define READY 1
#defien RUNNING 2 
#define BLOCK 3
//...struct task_struct
{int status;//就是上面定义的宏//...
}

  现在,我们能把各个状态都具象化成宏了,而这些 状态决定了进程的后续动作,Linux中可能同时运行多个进程,OS就要根据进程的状态来决定下一步做什么。

在这里插入图片描述
  以上可能是某个教材的进程状态图,我们接下来介绍的就是,运行、阻塞、和挂起 状态。


✈️运行状态

  进程有一个状态叫做 运行状态,很多人以为只有当CPU执行到当前进程时,才能称为当前进程为运行状态,实则不然。

  每一个CPU其实都有一个运行队列,比如:

struct runqueue{//运行队列int count;task_struct *p;//指向进程
}

在这里插入图片描述
  此时,整个队列的进程状态都为运行状态,而运行状态的意思是:

  R(Running): 准备好被CPU随时调度。


✈️阻塞状态

  进程有时会处于一种特殊的状态,阻塞状态 我们前面scanf等待硬件资源就会把进程拉入到一个 阻塞队列(Blocked Queue) 当中,表示正在阻塞等待某种硬件资源,当获得硬件资源后就会从阻塞队列中退出,链入到运行队列当中。

  操作系统对下管理硬件资源,那么操作系统是如何管理这些硬件资源的?还是那六个字:先描述,再组织!

  将硬件资源描述为一个个属性,将这些属性组织起来称为结构体,那么从此以后,操作系统对硬件的管理就变为了对这个结构体对象的管理

struct device//硬件设备
{size_t type;//硬件类型,键盘、鼠标、磁盘,网卡等...//设备的操作方法//状态struct listnode node;task_struct *p;//指向进程//...
}

在这里插入图片描述
  所以我们能得出的结论是:

  当我们的进程在等待 软硬件资源 的时候,资源如果没有就绪,我们的进程PCB就只能: 1.将自己设置为阻塞状态。2.将自己的PCB链入等待资源的等待队列 (通常是资源竞争)


✈️挂起状态

  进程还存在一种挂起状态,这种状态与计算机内存有关系,当 计算机内存非常吃紧的时候,操作系统为了 保证向上提供良好的运行环境,所以操作系统一定会把需要等待资源的进程进行特殊处理,将内存资源释放一些,以便于 向上提供良好的环境

  比如说阻塞队列和等待队列,这些需要等待软硬件资源的进程,此时,这些进程不用我们的资源但是还占用我们的资源,所以OS就会将这些进程的代码和数据 唤入 到磁盘中的 swap分区

在这里插入图片描述
  其实这种挂起状态为 阻塞挂起,当然不排除有些教材里有其他挂起,但是我们就谈这一种。

  唤出 仅仅是将进程的 代码和数据 唤出,进程的 task_struct 一定要保留在内存中,不然OS就没法确定这个进程的状态了。

  可能在有些书里还有其他挂起,但是挂起的原因只有一个:一定是因为某种资源的紧缺才会挂起。


📒✏️总结

  •   每个进程都有自己的进程状态,在C语言中以 的方式体现,有了状态操作系统就知道下一步要做什么
  •   进程中存在许多队列,CPU执行的队列叫做 运行队列,阻塞等待软硬件资源的叫做 阻塞队列 和 等待队列
  •   进程排队是进程的 task_struct 在排队,而不是可执行程序在排队。并且只要是排队,就 一定是在等待某种资源分配
  •   挂起状态跟 内存有关,当内存状态吃紧时,将需要等待软硬件资源的进程的代码和数据唤出到 硬盘的 swap分区,需要时再唤入。

在这里插入图片描述

  创作不易,如果这篇文章对您有帮助的话,还望留下一个小小的三连呀~~

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

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

相关文章

MC78L05ACDR2G线性稳压器芯片中文资料规格书PDF数据手册引脚图参数图片价格

产品概述&#xff1a; MC78L00A系列线性稳压器价格便宜&#xff0c;易于使用&#xff0c;适用于各种需要最高100mA的调节电源的应用。与大功率MC7800和MC78M00系列一样&#xff0c;这款稳压器也提供内部电流限制和高温关断&#xff0c;因此非常坚固耐用。在很多应用中&#xf…

R语言:如何基于地球外辐射(Ra)和相对日照(n/N)计算太阳辐射Rs?

正在编写相关软著&#xff0c;借此机会了解R语言的基本语法和一些处理流程&#xff0c;所以解释稍微繁琐。 Note&#xff1a; 使用的R语言版本是 R version 4.3.2 (2023-10-31 ucrt) 使用的RStudio编辑器版本是&#xff1a; 01 基于随机森林的插值填补缺失值 这是目前处理…

冲动是魔鬼,工作不顺心时不要把坏脾气带给家人

今天与一个跟踪了很久的客户准备签合同了&#xff0c;客户突然反悔&#xff0c;为此与他周旋了一整天&#xff0c;忙碌得一口水都没有喝。回到小区坐在车里抽着烟&#xff0c;久久不愿回家&#xff0c;只想一个人坐着&#xff0c;疲惫、无奈。这个月的奖金似乎又将成为泡影。 …

MySQL语法分类 DDL

DDL(操作数据库、表) 数据库操作(CRUD) C(Create):创建 //指定字符集创建 create database db_1 character set utf8;//避免重复创建数据库报错可以用一下命令 create database if not exists db_1 character set utf8;R(Retrieve):查询 //查询所有数据库的名称 show datab…

spark基本原理UI界面解读

这里是引用 1 八股文 1.1 基本原理 driver节点是整个应用程序的指挥所 指挥官是sparkcontext 环境&#xff1a;构建一个集群 应用程序提交 确定主节点&#xff0c;确定指挥所driver&#xff0c;确定指挥官sparkcontext sparkcontext会向资源管理器申请资源 会将作业分…

拿捏指针(二)

个人主页&#xff1a;秋邱博客 所属栏目&#xff1a;C语言 &#xff08;感谢您的光临&#xff0c;您的光临蓬荜生辉&#xff09; 目录 前言 数组与指针 数组名的理解 指针数组与数组指针 指针数组 数组指针 数组传参 一维数组传参的本质 二维数组传参的本质 二维数组…

【应急响应靶场web2】

文章目录 前言 一、应急响应 1、背景 2、webshell查杀 3、日志排查 1&#xff09;apache日志 2&#xff09;nginx日志 3&#xff09;ftp日志 4、隐藏账户 5、文件筛选 二、漏洞复现 总结 前言 靶场来源&#xff1a;知攻善防实验室 一、应急响应 1、背景 小李在某…

实现HBase表和RDB表的转化(附Java源码资源)

实现HBase表和RDB表的转化 一、引入 转化为HBase表的三大来源&#xff1a;RDB Table、Client API、Files 如何构造通用性的代码模板实现向HBase表的转换&#xff0c;是一个值得考虑的问题。这篇文章着重讲解RDB表向HBase表的转换。 首先&#xff0c;我们需要分别构造rdb和hba…

关于Transfomer的思考

为何诞生 在说transformer是什么&#xff0c;有什么优势之类的之前&#xff0c;先谈一谈它因何而诞生。transformer诞生最重要的原因是早先的语言模型&#xff0c;比如RNN&#xff0c;由于其本身的训练机制导致其并行度不高&#xff0c;特别是遇到一些长句子的情况下。其次&…

论文阅读——MoCo

Momentum Contrast for Unsupervised Visual Representation Learning 动量在数学上理解为加权移动平均&#xff1a; yt-1是上一时刻输出&#xff0c;xt是当前时刻输入&#xff0c;m是动量&#xff0c;不想让当前时刻输出只依赖于当前时刻的输入&#xff0c;m很大时&#xff0…

DP-不同的二叉搜索树

给你一个整数 n &#xff0c;求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种&#xff1f;返回满足题意的二叉搜索树的种数。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;5示例 2&#xff1a; 输入&#xff1a;n 1 输出&#xff1a;1提…

kubernetes部署集群

kubernetes部署集群 集群部署获取镜像安装docker[集群]阿里仓库下载[集群]集群部署[集群]集群环境配置[集群]关闭系统Swap[集群]安装Kubeadm包[集群]配置启动kubelet[集群]配置master节点[master]配置使用网络插件[master]node加入集群[node]后续检查[master]测试集群 集群部署…