当前位置: 首页 > news >正文

【Linux】进程初阶(2)——进程状态

目录

前言

2.1进程状态理解

2.2Linux下的进程状态

2.2.1简介

2.2.2状态详解

2.3僵尸进程与孤儿进程

2.3.1僵尸进程

2.3.2孤儿进程


前言

根据前面对进程的基本了解,浅浅了解了进程。下面更进一步探讨进程,来了解Linux下的进程状态。更多Linux学习内容参考:Linux专栏

2.1进程状态理解

在宏观的计算机系统中,一般进程状态及状态间关系如下图:

而其中最核心的是运行、阻塞和挂起状态,下面让我们一起来认识这三个状态。

在操作系统为进程分配硬件资源时,每个硬件程序会有一个调度队列,队列中会储存每个进程的PCB,而一般我们将处于CPU调度队列当中的进程称为运行状态。

下面以Linux的task_strcut为例:操作系统为管理硬件,也会对硬件进行描述,类似有一个储存硬件信息的结构体,在该结构体中又会有相应进程的调度队列

像在CPU调度队列的进程状态就是运行状态。

对于阻塞状态,我们先来看看程序运行时怎样就是阻塞:

#include<stdio.h>
#include<unistd.h>int main()
{int a;printf("等待键盘输入:");scanf("%d", &a);printf("%d\n", a);return 0;
}

运行结果如下:

这时等待键盘输入的状态就可以称为进程阻塞了,此时的进程需要调用键盘输入,即等待键盘就绪,更进一层面也就是等待硬件就绪。那么程序怎么知道硬件就没就绪呢?操作系统作为软件与硬件的管理者,也会对硬件进行结构体描述,在每个硬件的结构体中也会有一个等待队列。因此将进程结构体处于除CPU之外队列的状态,称为阻塞状态。

那什么又叫挂起呢?挂起是主要应对进程在运行过程中内存不足的情况。在操作系统硬件的磁盘中,会有一个swap分区,用来做内存不足的情况下,来储存还未来得及运行的进程代码和数据。此时进程处于swap分区的状态叫做挂起状态。

除此之外,像例子中这种在运行过程时挂起的状态叫做运行挂起;而若进程在等待硬件就绪处于阻塞状态时被挂起,则称为阻塞挂起。

当内存足够时,储存在swap分区中的进程就是通过swap out换出到内存,而若仍然内存不足,操作系统则会选择直接删除部分进程。


2.2Linux下的进程状态

2.2.1简介

上面进程状态主要是对于全部操作系统的设计哲学,而对于特定的操作系统会有所差别。下面以Linux系统为例进行讲解。

通过Linux源码查看,可得Linux的进程状态主要分为如下几类:

*/
*The task state array is a strange "bitmap" of
*reasons to sleep. Thus "running" is zero, and
*you can test for combinations of others with
*simple bit tests.
*/
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 */
}

为了更方便了解操作系统中的进程的状态,我们可使用ps aux | ps axj 命令来查看进程状态。

• a:显⽰⼀个终端所有的进程,包括其他⽤⼾的进程。 
• x:显⽰没有控制终端的进程,例如后台运⾏的守护进程。 
• j:显⽰进程归属的进程组ID、会话ID、⽗进程ID,以及与作业控制相关的信息 
• u:以⽤⼾为中⼼的格式显⽰进程信息,提供进程的详细信息,如⽤⼾、CPU和内存使⽤情况等 

2.2.2状态详解

R状态

R(runing)状态表示进程正在运行

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>int main()
{pid_t id = getpid();while(1){printf("这是一个进程,pid为:%d\n", id);sleep(1);}return 0;
}

我们通过运行自己创建的进程来看看是不是处于R状态:

可以看到这时我们创建的进程pid为8243,而8243的状态为S+,那我们程序正在运行,应该是R状态为什么会是S+状态呢?

S状态

S(sleeping)在Linux中称为浅度睡眠状态,与操作系统原理中的阻塞状态类似,进程中需要调用某个硬件,并且正在等待该硬件就绪。

而在状态后面带个"+"则代表该进程属于前台进程。

我们的进程处于S状态的主要原因是在程序中调用的printf,而printf本质是向显示器上打印数据,且大部分时间是在等待显示器这个硬件资源,因此就处于S。

只需要我们将printf取消调用就是能看见R状态

可以看到此时我们的process进程就处于R状态了。

D状态

D(disk sleeping)状态在Linxu中称为深度睡眠状态,是Linux中特有的一种状态。

要谈深度睡眠就要与浅度睡眠进行对比。浅度睡眠是为了表示正在等待硬件就绪的状态,而深度睡眠则表示一种等待内存给完资源的状态。例如一个进程在运行时需要内存开辟500MB大小的空间给进程,而内存开辟数据空间需要时间,此时进程就在等待内存开辟完成,若此时进程像别的硬件等待一样处于S状态而被优化关闭,那么就会造成内存会没来得及开辟完成,进程就提前结束的情况,进而造成数据丢失。因此Linux中设立了D状态,以防止处于该状态的进程被提前结束。

T状态与t状态

T(stopped)状态在Linux中称为暂停状态。而t状态则称为追踪暂停状态,一般只在程序被调试的过程中产生。

暂停状态与休眠状态不同的是T状态一般为进程被外部信号主动暂停且只能通过信号唤醒,而S状态则是进程一般在等待某个事件或资源到来时主动进入。

X状态

X(dead状态)也被称为消亡状态,为瞬时状态,一般无法被观测到。

谈到X状态,那么已经消亡的进程就会马上消失吗?例如现实世界生物的死亡,我们会先确定其死因。同样在操作系统中一个进程的消亡也需要检查其消亡后的进程信息,此时操作系统不会马上将消亡进程的资源进行释放,而是对其进行临时保留。此时进程处于已结束而资源未被回收的状态称为Z状态(僵尸状态)。

Z状态

Z(zombie)状态也叫僵尸状态,是进程已消亡而其资源仍被操作系统保留的一种状态。


2.3僵尸进程与孤儿进程

下面进一步探讨父子进程间消亡的先后。

2.3.1僵尸进程

当进程消亡后会先处于Z状态,而若未将该资源回收,会一直处于僵尸状态,此时的进程被称为僵尸进程。

在操作系统中运行进程一般都是bash为父进程,因此会自动回收。而若我们自己创建的父子进程中将子进程先消亡,而父进程保持运行,而父进程中不对子进程消亡后资源进行回收,那么子进程就会成为僵尸进程:

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>int main()
{pid_t id = fork();if(id == 0){int i = 5;for(i = 0; i < 5; i++){printf("这是子进程,pid为%d\n", getpid());sleep(1);}}else{while(1){printf("这是父进程,pid为%d\n", getpid());sleep(1);}}return 0;
}

下面我们来查看下运行进程的状态

可以看到当子进程运行结果,而父进程仍在运行而未对子进程资源进行回收时,子进程就会一直处于僵尸状态,也就是说此时的子进程就会成为僵尸进程。而僵尸进程一直占用内存资源,导致其他进程所能有的资源越来越少,若僵尸进程越来越多,最后就会导致操作系统的卡顿甚至崩溃。

2.3.2孤儿进程

子比父先亡,那么子进程就有可能成为僵尸进程;那如果父进程比子进程先消亡呢?

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>int main()
{pid_t id = fork();if(id != 0){int i = 5;for(i = 0; i < 5; i++){printf("这是父进程,pid为%d\n", getpid());sleep(1);}}else{while(1){printf("这是子进程,pid为%d\n", getpid());sleep(1);}}return 0;
}

可以看到此时pid为8464的子进程在父进程优先消亡后,父进程变为了pid为1的进程,pid为1的进程是什么呢?Linux系统下我们通过top命令来查看所有运行的进程:

可以看到此时pid为1的是一个叫systemd的进程,也就是系统进程。

那么为什么父进程消亡后要将其子进程的父进程变为系统进程呢?子进程消亡后的资源需要其父进程进行回收,若父进程比子进程优先消亡而不改变其父进程,那么就是导致父进程消亡的同时间接造成了僵尸进程问题。因此对于父进程优先消亡子进程,操作系统会统一将其父进程变为pid为1的系统进程,方便其后的资源回收,防止内存泄露。

http://www.dtcms.com/a/544804.html

相关文章:

  • WSL2 Ubuntu cuda驱动问题解决和CUDA Toolkit安装
  • 深圳市住房建设局网站个性婚纱摄影
  • SQLite 约束 (Constraints) 面试核心知识点
  • 使用J-Link Attach NXP S32K3导致对应RAM区域被初始化成0xDEADBEEF
  • 电子商务网站建设与维护展望分销系统微信
  • 变量与可变性
  • STM32 GPIO其他少见的库函数解析
  • 云栖实录|驰骋在数据洪流上:Flink+Hologres驱动零跑科技实时计算的应用与实践
  • 百度免费网站空间中国铁建股份有限公司
  • 【Git】版本更新
  • 网站建设与维护就业前景电商培训类网站模板下载
  • Android电池优化和前后台任务
  • 使用 Java 将 Excel 工作表转换为 CSV 格式
  • Kotlin基础类型扩展函数使用指南
  • 城市建设网站做印刷品去哪个网站
  • 怎么查网站到期时间php网站搭建环境
  • 汽车行业SCRM:企业微信+服务商模式破解汽车服务行业痛点的案例分析
  • 【第五章:计算机视觉-项目实战之推荐/广告系统】3.精排算法-(4)重排算法:MMR、DPP原理精讲
  • Xamarin.Forms菜鸟笔记--10.获取点击/滑动 Image位置
  • 网络环路“侦探”指南:如何快速定位与根除网络风暴
  • Android 自定义Switch
  • HBuilder 上架 iOS 应用全流程指南:从云打包到开心上架(Appuploader)上传的跨平台发布实践
  • PHP基础知识
  • Obsidian 入门教程
  • 响应式购物网站模板广州网站优化电话
  • 中山 网站建设 骏域做ag视频大全网站
  • Vue二进制数据渲染成图片
  • 未来智能网联汽车的网络安全档案建立方法
  • 防止表单重复提交功能简单实现
  • 网络安全等级保护测评高风险判定实施指引(试行)--2020与2025版对比