Linux进程理解【进程状态】

news2024/9/23 23:31:07

Linux进程理解【进程状态】

进程运行时,进程会被CPU调度,但系统中存在多个进程,进程运行的先后顺序等等该怎么保证呢?OS将进程分成了运行、睡眠、休眠、暂停、死亡等几种状态来对进程进行管理,下面我将带大家学习进程各种状态的应用场景及作用

文章目录:

  • Linux进程理解【进程状态】
  • 1. 阻塞和挂起
  • 2. 进程状态
    • 2.1 运行状态 R
    • 2.2 睡眠状态 S
    • 2.3 休眠状态 D
    • 2.4 暂停状态 T
    • 2.5 死亡状态 X
    • 2.6 僵尸状态 Z
  • 3. 孤儿进程

1. 阻塞和挂起

阻塞

  • 阻塞就是进程因为等待某种条件就绪,而导致的一种不推进的状态
  • 简单来说就是,进程卡住了,原因是在等待某种资源
  • 从数据结构角度来理解,阻塞就是不被调度,这一定是因为进程task_struct结构体需要在某种被OS管理的资源下排队

举个例子,我们在使用到scanf函数时,当我们运行程序,光标会一直到控制台闪烁,实际上此时这个进程就是阻塞状态,它是在等待键盘的输入,也就是在等待键盘输入这一资源

为什么要阻塞呢?

  • 进程要通过等待的方式,等具体的资源被别人用完之后,再被自己使用,阻塞就是进程等待某种资源就绪的过程

挂起

  • 挂起状态就是当CPU资源不足时,OS将数据和代码(进程)交换到磁盘中挂起,此时内存中只有PCB

举个例子,我们在下载软件时,下载这个进程就会被加载到内存中,此时如果突然断网了,就会阻塞(缺少网卡资源),由于这里进程暂时不会被运行,资源放在内存中就会浪费空间,OS就会将代码和数据(进程)暂时存放到磁盘中,等到有网了再从磁盘中拿取,这个过程就是挂起状态,可以说挂起是一种特殊的阻塞状态

2. 进程状态

Linux下的进程状态

进程是什么状态一般是看进程在那个队列排队,也就是在那个硬件资源排队

kernel源代码定义:

/*
* 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 */
};

几种状态的解释

  • R运行状态(running): 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里
  • S睡眠状态(sleeping): 意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠)
  • D磁盘休眠状态(Disk sleep):有时候也叫不可中断睡眠状态,在这个状态的进程通常会等待IO的结束
  • T停止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行
  • X死亡状态(dead):这个状态只是一个返回状态,你不会在任务列表里看到这个状态

2.1 运行状态 R

按照以往的观点,程序一旦运行起来了,那么该程序就是处于运行状态,真的是这样吗?下面我们来看一个例子:

Makefile文件

myproc:mytest.c
	gcc -o myproc mytest.c

.PHONY:monitor
monitor:
	ps ajx | head -1 && ps ajx | grep myproc | grep -v grep 

.PHONY:clean
clean:
	rm -f myproc

这里可以直接将监视指令写入Makefile文件中,使用起来更加方便

下面我们运行监视起来看看现象

通过监视可以观察到此时的进程状态为S+,也就是睡眠状态,+ 号表示当前进程在前台运行

这是为什么呢,难道程序没有运行吗?

  • printf库函数是向外设打印信息,当CPU执行printf库函数时,就需要访问外设,但是这里如果时频繁打印的时候,CPU的运行速度是非常快的,外设和CPU的速度相差太大,导致外设就不一定是就绪的,那么这里就会产生阻塞,这个进程就会被放在对应的外设的结构体队列中排队 。

  • 其实程序运行了,但是我们很难捕捉到,大多数时间,进程都在外设等待队列中排队,导致效果上是休眠状态

这里如果我们去掉printf这一条需要访问外设的语句,进程就不会发生排队阻塞了,此时就可以观察到是运行状态

注意:R状态表示进程在运行,但不一定是在CPU上运行,进程在运行队列中排队也算运行状态

2.2 睡眠状态 S

睡眠状态S的本质就是进程阻塞,表示进程等待某种资源,在上面的测试中已经体现了

进程处于睡眠志状态我们可以通过ctrl + c来终止进程

当进程是在后台运行时,状态表示没有 + 号,此时ctrl + c是无法终止进程的,需要使用kill -9 PID来终止进程

2.3 休眠状态 D

休眠状态D是一种特殊的睡眠状态,又被称为不可中断睡眠状态,休眠状态下的进程是无法终止的,只能等到拿到所需资源,阻塞结束后,进程才会停止休眠状态

休眠状态比较少见,一般会出现于IO阻塞,这个状态的进程通常会等待IO的结束。系统不能出现D状态,出现D状态说明磁盘被占用空间很大,此时这个进程不能删除,一直等到数据被CPU处理完后这个进程才可中断,此时就表示系统离宕机不远了

2.4 暂停状态 T

可以通过指令使进程处于暂停状态T

  • kill -19 PID 暂停指定进程
  • kill -18 PID 恢复进程暂停

使用kill -19 PID 暂停进程

使用kill -18 PID 恢复进程暂停

可以看到此时恢复暂停后,进程状态为S,没有+表示进入了后台睡眠状态,此时使用ctrl+c是无法终止进程的,只能使用kill -9 PID来终止

gdb 中调试代码时,打断点本质上就是 使 进程 在指定行暂停运行,此时 进程 处于 t状态,也就是追踪暂停状态

2.5 死亡状态 X

当进程被终止后,就是处于死亡状态X,无法在任列表中看到这个状态,死亡状态只是一个返回状态

2.6 僵尸状态 Z

僵尸状态Z引入

  • 在多进程执行任务时,如果一个进程退出了,马上就成为了死亡X状态,bash作为父进程,是没有机会拿到退出结果的
  • 为了解决这一问题,Linux下当子进程终止后,不会立即退出,而是会维持一个僵尸Z状态,方便父进程来读取子进程的退出结果

bash有僵尸进程的回收机制,直接在bash环境下终止子进程无法观察到僵尸状态,这里我们可以使用上文中讲到的fork()函数来创建父子进程关系,观察僵尸状态

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <assert.h>
 
int main()
{
  pid_t ret = fork(); //获取返回值
  assert(ret != -1);  //创建失败的情况
 
  if(ret == 0) //子进程
  {
    while(1)
    {
 
      printf("我是子进程, 我的PID是: %d,PPID是: %d\n", getpid(), getppid());
      sleep(1);
    }
  }
  else if(ret > 0) //父进程
  {
    while(1)
    {
      printf("我是父进程, 我的PID是: %d,PPID是: %d\n", getpid(), getppid());
      sleep(1);
    }                                                      
  }
  else
  {
    printf("进程创建失败!");
  }
 
  return 0;
}

运行监视起来观察现象

这时我们终止子进程,由于子进程没有被回收,此时就是处于僵尸状态

僵尸进程的危害:

  • 僵尸状态一直不退出,PCB需要一直维护,浪费内存资源
  • 僵尸进程如果不被回收,还会导致内存泄漏和标识符占用问题

至于如何避免僵尸进程造成的问题,我会在后续文章详细讲解

3. 孤儿进程

上面了解到了父子进程运行时,当子进程终止后,并不会直接结束,而是处于僵尸状态,方便父进程来读取子进程的结果。

那么如果反过来,父进程先结束,子进程会处于什么状态呢?

下面我们再来启动上面的程序实践一下

然后终止父进程

这里我们观察到,终止父进程后子进程的父进程变成了1号进程

此时的子进程就是孤儿进程

  • 当父进程退出后,子进程会被OS自动领养
  • 子进程的父进程就变成了1号进程,即OS,这个被领养的子进程就是孤儿进程

为什么子进程会被OS领养呢?

  • 如果不被领养,子进程后续再退出,就会变成一个无人回收的僵尸进程,会造成内存泄漏的问题

Linux进程理解—进程状态,到这里就介绍结束了,本篇文章对你由帮助的话,期待大佬们的三连,你们的支持是我最大的动力!

文章有写的不足或是错误的地方,欢迎评论或私信指出,我会在第一时间改正

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

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

相关文章

工作--数组

一、遍历数组 1、filter&#xff1a; 新数组、return、条件表达式 &#xff08;不改变原数组&#xff09; 把满足条件的元素返回给 新数组&#xff0c;filter返回的是新数组 &#xff01;&#xff01;&#xff01;&#xff01; 赋值&#xff0c;会直接覆盖掉原来的值 使用…

react useState useEffect useMemo实际业务场景中的使用

下面的代码实现了上面图片的功能 import React, { useMemo } from "react"; import "./HomeHead.less"; import Img from "../assets/images/timg.jpg";const HomeHead function HomeHead(props) {{ /*父组件传过来的值 */}let { today } pro…

Gabor Filters

Gabor Filters: Manjunath, B. S., & Ma, W. Y. (1996). Texture features for browsing and retrieval of image data. IEEE Transactions on Pattern Analysis and Machine Intelligence, 18(8), 837-842. Gabor滤波器是一种基于Gabor函数的特定频率和方向选择性滤波器。…

Go语言之流指针类型,new函数

计算机中所有的数据都必须放在内存中&#xff0c;不同类型的数据占用的字节数不一样&#xff0c;例如 int 占用 4 个字节。为了正确地访问这些数据&#xff0c;必须为每个字节都编上号码&#xff0c;就像门牌号、身份证号一样&#xff0c;每个字节的编号是唯一的&#xff0c;根…

MySQL-DDL-表结构操作

DDL&#xff08;表操作&#xff09; 表的创建 以具体代码的显示展示如何进行数据表的创建 CREATE DATABASE <数据库名>;CREATE TABLE <表名> (<列名1> <数据类型1> <约束>,<列名2> <数据类型2> <约束>,... ) 具体代码示例&am…

基于Spring Boot的高校专业学习预警系统设计与实现(Java+spring boot+MySQL)

获取源码或者论文请私信博主 演示视频&#xff1a; 基于Spring Boot的高校专业学习预警系统设计与实现&#xff08;Javaspring bootMySQL&#xff09; 使用技术&#xff1a; 前端&#xff1a;html css javascript jQuery ajax thymeleaf 微信小程序 后端&#xff1a;Java sp…

C++正则表达式校验某个字符串是否是合格的email

C正则表达式校验某个字符串是否是合格的email 可以借助正则表达式校验某个字符串是否是合规的电子邮箱。对于邮箱的正则表达式有严格的模式&#xff0c;如&#xff1a;^[a-zA-Z0-9_&*-](?:\\.[a-zA-Z0-9_&*-])*(?:[a-zA-Z0-9-]\\.)[a-zA-Z]{2,7}$ 对应的C实现如下&a…

测试基础概念及常见开发模型和测试模型

目录 1.需求的概念 2.测试用例 3.什么是BUG 4.软件的生命周期 5.开发模型和测试模型 开发模型 瀑布模型 快速原型模型 螺旋模型 增量模型 敏捷方法 scrum三大角色 测试模型 V模型 W模型 1.需求的概念 衡量软件测试结果的依据—需求 概念&#xff1a;满足用户期…

变量与数据类型

专栏简介&#xff1a;本专栏作为Rust语言的入门级的文章&#xff0c;目的是为了分享关于Rust语言的编程技巧和知识。对于Rust语言&#xff0c;虽然历史没有C、和python历史悠远&#xff0c;但是它的优点可以说是非常的多&#xff0c;既继承了C运行速度&#xff0c;还拥有了Java…

互联网未来信任锚点,后量子计算标准与迁移势在必行

作者 | 宋慧 出品 | CSDN 云计算 图片 | 视觉中国 IT、数字化正在深刻改变和加速全行业的效率与创新。不过&#xff0c;互联网的信息通信安全基石——密码学技术仍在使用第一代公钥密码算法&#xff0c;而随着量子计算的产生发展&#xff0c;以离散对数和大数分解这类等价的数…

深入理解网络通信和TCP、IP协议-01

1、网络协议 计算机网络是什么&#xff1f; 随着计算机技术发展&#xff0c;计算机的体积和价格都在下降&#xff0c;之前计算机多用于研究机构&#xff0c;现 阶段逐步进入一般的公司用于办公。原来计算机之间传输数据需要通过软盘等第三方存储介 质进行转存&#xff0c;人们…

【CXL】CXL ATS 介绍

&#x1f525;点击查看精选 CXL 系列文章&#x1f525; &#x1f525;点击进入【芯片设计验证】社区&#xff0c;查看更多精彩内容&#x1f525; &#x1f4e2; 声明&#xff1a; &#x1f96d; 作者主页&#xff1a;【MangoPapa的CSDN主页】。⚠️ 本文首发于CSDN&#xff0c…

《代码随想录》专题:二叉树的遍历

0、二叉树的遍历方式总结 二叉树主要有两种遍历方式 深度优先遍历&#xff1a;先往深走&#xff0c;遇到叶子节点再往回走。广度优先遍历&#xff1a;一层一层的去遍历。 从深度优先遍历和广度优先遍历进一步拓展&#xff0c;才有如下遍历方式 深度优先遍历 前序遍历&#xff…

【网络编程】网络编程核心概念与模式

配套环境 vscode、gcc、ubuntu22.04 概念描述 网络编程的本质 使用操作系统提供的接口函数&#xff0c;使得应用程序具备收发网络数据的能力。 网络接口在代码层面是操作系统提供的函数 应用程序通过网络接口使用操作系统的联网能力 网络编程核心概念 协议&#xff1a;为进…

STM32——led灯的点亮+闪烁+流水灯的实现

文章目录 一、LED点亮1.原理2.寄存器方式--代码3.库函数--代码4.结果展示 二、LED闪烁三、LED流水灯1.代码2.结果展示 一、LED点亮 1.原理 其方式有两种一种是寄存器方式一种是库函数方式&#xff0c;但其原理都是一样的。如原理图所示&#xff0c;与LED相连接的IO口置低电平…

HTML学习 第一部分(前端学习)

参考学习网站: 网页简介 (w3schools.com) 我的学习思路是&#xff1a;网站实践视频。 视频很重要的&#xff0c;因为它会给你一种开阔思路的方式。你会想&#xff0c;噢&#xff01;原来还可以这样。这是书本或者网站教程 所不能教给你的。而且&#xff0c;对一些教程&#…

【深度解析】OSPF-开放式最短路径优先协议

目录 重点&#xff1a; VPN---Virtual Private Network(虚拟专用网络隧道) OSPF网络类型&#xff1a; 表格视图&#xff1a; P2P---点对点协议 BMA---广播多路访问网络 NBMA---非广播多路访问网络 P2MP---点对多点协议 OSPF认证&#xff1a;检测类型&#xff0b;密码 …

陪诊师接单app开发|陪诊小程序开发|陪诊师接单系统开发

随着人们健康意识的提高和医疗服务的不断完善&#xff0c;陪诊服务逐渐受到人们的关注和需求。为了满足顾客的需求&#xff0c;陪诊小程序应运而生。下面将介绍陪诊小程序开发的几个优势。   1. 提供方便的预约和服务体验   陪诊小程序可以让顾客随时随地通过手机预约陪诊服…

Java034——反射(Reflection)

一、Java中的反射及作用 Java的反射(reflection)机制是指在程序的运行状态中&#xff1a; 可以构造任意一个类的对象&#xff0c;可以了解任意一个对象所属的类&#xff0c;可以了解任意一个类的成员变量和方法&#xff0c;可以调用任意一个对象的属性和方法。 一句话&#…

3.类与对象

Java作为一种面向对象语言。支持以下基本概念&#xff1a; 多态继承封装抽象类对象实例方法重载 1.类与对象 对象&#xff1a;对象是类的一个实例&#xff0c;有状态和行为 类&#xff1a;类是一个模板&#xff0c;它描述一类对象的行为和状态 public class Dog {String bree…