[Linux 进程(二)] Linux进程状态

news2024/11/16 19:51:47

在这里插入图片描述

文章目录

  • 1、进程各状态的概念
    • 1.1 运行状态
    • 1.2 阻塞状态
    • 1.3 挂起状态
  • 2、Linux进程状态
    • 2.1 运行状态 R
    • 2.2 睡眠状态 S
    • 2.3 深度睡眠 D
    • 2.4 停止状态 T
    • 2.5 僵尸状态 Z 与 死亡状态 X
      • 孤儿进程

Linux内核中,进程状态,就是PCB中的一个字段,是PCB中的一个变量,一般是宏定义出的一批数字。
为了弄明白正在运行的进程是什么意思,我们需要知道进程的不同状态。一个进程可以有几个状态(在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 */
};

再配上下面的图,我们看看各进程状态之间的转换:
在这里插入图片描述

状态的变化,本质就是修改整形变量。
看到这大家可能还是比较懵的,下面我们就来细看每一种状态。
首先我们先看教材上的进程状态,再具体到Linux下的进程状态。

1、进程各状态的概念

1.1 运行状态

每个CPU在系统层面都会维护一个运行队列。(n个CPU就会维护n个运行队列)
在这里插入图片描述
什么叫做运行状态?
只要在运行队列中的进程,状态都是运行状态。
只要是在运行队列中的进程,它的PCB中状态字段就是R,数据是准备就绪的,只等CPU运行了。

1.2 阻塞状态

进程 = 代码 + PCB(内核数据结构)。而我们的代码中,一定或多或少回访问系统中的某些资源(比如:磁盘、显示器、键盘、网卡等)。
我们下面举例来理解一下阻塞状态,下面是一整个链路,串起来理解:

1、当我们是C/C++代码,代码中有 scanf/cin,需要从键盘中输入时,我们用户就是不输入,键盘上的数据就是没有准备就绪的,这就是进程所要访问的数据没有就绪,即不具备访问条件,导致进程的代码无法向后执行。
2、访问的数据没有就绪,操作系统一定是最先知道的,因为操作系统是一款搞管理的软件,它管理计算机的所有软硬件。操作系统管理硬件,本质也是管理数据,“先描述,再组织”。
3、当进程在CPU中被运行的时候,用户一直不输入,这时访问的数据是没有就绪的,于是PCB就被操作系统从运行队列中放到硬件的等待队列中,PCB中状态字段就被改为 阻塞状态,然后去排队等待。一旦用户输入,数据状态立马就被改为了就绪状态,操作系统再将PCB放入到运行队列(将进程唤醒),并将PCB状态改为运行状态,CPU继续开始运行进程。
在这里插入图片描述

总结:
1、当PCB不在CPU所维护的运行队列,而在硬件的等待队列中,此时状态就是阻塞状态。
2、进程状态变化的本质:更改PCB中status整数变量; 将PCB链入到不同的列队中。
3、这里的所有过程,只和进程的PCB有关,与进程的数据代码都无关。
4、操作系统中,会有非常多的队列,运行队列、等待硬件的设备等待队列等。

这里我们也就不难想到,平时使用计算机时,启动了非常多的进程后,为什么会那么卡呢?
其实就是操作系统以我们能感知的时间里,将进程的状态不断在改变。

1.3 挂起状态

如果一个进程当前被阻塞了,这个进程等待的资源是没有就绪的,该进程就没有办法被调度。
如果此时,恰好 操作系统内的内存资源严重不足(前提) 了,怎么办?
此时我们阻塞进程的代码和数据就可以先写入磁盘中,等数据就绪后,再拷贝到内存中,这时就叫做 阻塞挂起状态(结果)这里将内存数据置换到磁盘,针对所有的阻塞进程。这个过程虽然慢了点,但是与资源严重不足将要宕机相比,慢点是可以接收的。

这里数据会被置换到swap分区。一般swap分区大小与内存大小差不多大,如果很大,swap分区很难被写满,内存稍微不足,操作系统就会将数据换出到swap分区,频繁的换出就会导致效率变慢。因此设置小点就会倒逼操作系统自己来处理,而不是频繁使用置换算法,提高效率。
当进程被os调度,曾经被置换出去的进程代码和数据,又要被重新加载到内存。
在这里插入图片描述

具体还有就绪挂起,在运行队列中,但是还没有被调度的进程,代码和数据被换出,等调度的时候再换入,这就是就绪挂起,这样会导致效率变低。

2、Linux进程状态

2.1 运行状态 R

  • R运行状态(running) : 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里。
    我们写一段C语言代码来跑一下,看看进程是什么状态。
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main()
{
    while(1)
    {
        printf("Hello Linux, pid:%d\n", getpid());
    	sleep(1);
    }
    
    return 0;
}

我们编译完代码后运行,并用 ps ajx 命令查进程,看看进程状态:

ps ajx | head -1 && ps ajx | grep mytest | grep -v "grep"

在这里插入图片描述
这里明明是运行着呢,为什么状态是S呢?
这是因为CPU跑代码很快,但是外设显示器的速度很慢,大多时间都是在等待显示器。这就是访问了外设,外设数据没有就绪,进程是阻塞状态。

我们去掉 printf 语句,不让代码去访问外设,直接运行,看到的就是R 运行状态了。
在这里插入图片描述
在这里插入图片描述

大家一定还有疑问,我们说的是R与S状态,但是查出来的却是R+与S+,这是怎么回事呢?
+表示的是前台进程的意思,所谓前台进程就是推在前台的,一旦启动我们的bash(命令行解释器)就无法在使用了,前台进程可以使用 ctrl+c 终止掉的。
在这里插入图片描述

后台进程就是跑在后台的,不影响我们bash的工作(输入命令可以执行),只能使用 kill -9 pid 来终止。后台进程的状态就没有+。
后台进程的启动:./exe &
在这里插入图片描述

2.2 睡眠状态 S

  • S睡眠状态(sleeping): 意味着进程在等待事件完成浅度睡眠,可以被终止掉,会对外部信号做出响应。(这里的睡眠有时候也叫做可中断睡眠(interruptible sleep))。
    我们写一段C语言代码,编译后运行:
    在这里插入图片描述
    在这里插入图片描述
    此时我们不输入,进程就阻塞了,在Linux中具体的状态就是S。
    在这里插入图片描述
    S状态可以被终止掉,或者可以再换到运行状态。

2.3 深度睡眠 D

  • D磁盘休眠状态(Disk sleep)有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束。
    D状态我们不好演示,我们举例讲一下,什么时候是深度睡眠状态。
    如果我们的进程是往磁盘中做写入操作的时候,写入的数据量很大,这时是磁盘在工作了,进程就休眠了,但是写入成功与否,磁盘还要给进程反馈。恰巧此时内存资源严重不足,置换算法也解决不了时,(Linux下)操作系统是可以杀进程的,它肯定是不会杀掉运行状态的进程,所以它会杀掉睡眠中的进程,此时这个进程被杀掉了。这时磁盘没有将数据写入成功,后面还有进程需要向磁盘写数据,此时磁盘想给进程返回没有成功时,进程被杀掉了,磁盘只好将数据丢弃掉做后面的工作,进程也不知道是否写入成功。如果这是具体的银行10万条存款记录,这就是一次重大事故。
    因此,防止向磁盘写入重要数据时进程被终止掉,就有一个深度睡眠状态 D,深度睡眠状态下的进程是不可以被杀掉的。一般情况下,我们用户要是可以查到D状态,内存就很忙了,也就意味着几乎要宕机。

2.4 停止状态 T

  • T停止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。
    我们先来看看一些信号:
    在这里插入图片描述
    这些数字对应的信号,在Linux内核中其实是宏定义出来的。
    我们以下面的例子来看看,试一下暂停:
    在这里插入图片描述
    编译后运行:
    在这里插入图片描述
    我们发送信号让进程暂停了,此时我们发现,bash提示符在闪烁等待我们输入,一暂停进程就被改为后台进程了,不影响我们其他的操作。这时我们想要进程再运行起来,我们做下面的操作:
    在这里插入图片描述
    这很简单,但是我们为什么要将状态设置为停止状态呢?
    当进程访问软件资源的时候,可能暂时不让进程进行访问,就将进程设置为STOP。
    t 状态,是我们使用gdb调试代码时,追踪程序,遇到断点,进程就暂停了。
    在这里插入图片描述

这里我们能看到,当我们打了断点后,去运行程序,走到断点处状态变成了t,t表示tracing追踪的意思。
所以,不管是 T/t 都是阻塞状态,这里没有等待硬件资源,而是等待用户的指令,这就叫做 等待软件条件就绪。 因此在具体的os中这些都叫做阻塞状态。

2.5 僵尸状态 Z 与 死亡状态 X

  • X死亡状态(dead):这个状态只是一个返回状态,你不会在任务列表里看到这个状态。
  • Z 僵尸状态(zombie):一个比较特殊的状态。当进程退出并且父进程/OS(使用wait()系统调用,后面讲)没有读取到子进程退出的返回代码时就会产生僵死(尸)进程(父进程要知道子进程把任务完成的怎么样)。
  • 僵死进程会以终止状态保持在进程表(PCB)中,并且会一直在等待父进程读取退出状态代码。
  • 所以,只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入Z状态。 如果不及时回收,就会造成内存泄漏(字段会申请资源)。
    我们写一段C语言代码来验证一下 Z 状态,我们父进程不回收子进程:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main()
{
    pid_t id = fork();
    if(id < 0) return 1;
    else if(id == 0)
    {
        // child
        int cnt = 5;
        while(cnt)
        {
            printf("I am child, run times: %d\n", cnt--);
            sleep(1);
        }
        printf("I am child, dead: %d\n", cnt--);
        exit(2);
    }
    else                                                    
    {
        // father
        while(1)
        {
    		printf("I am father, running any time!\n");
            sleep(1);
	    }

        // 回收操作
    }
 
    return 0;
}

在这里插入图片描述
父进程没有回收子进程,子进程从S状态变为Z状态,defunct就是死者,死亡的意思。
僵尸进程的危害:

  • 进程的退出状态必须被维持下去,因为他要告诉关心它的进程(父进程),你交给我的任务,我办的怎么样了。可父进程如果一直不读取,那子进程就一直处于Z状态?是的!
  • 维护退出状态本身就是要用数据维护,也属于进程基本信息,所以保存在task_struct(PCB)中,换句话说, Z状态一直不退出, PCB一直都要维护?是的!
  • 那一个父进程创建了很多子进程,就是不回收,是不是就会造成内存资源的浪费?是的!因为数据结构对象本身就要占用内存,想想C中定义一个结构体变量(对象),是要在内存的某个位置进行开辟空间!
  • 内存泄漏 ?是的!

孤儿进程

刚我们讲的是子进程先退出,父进程不回收,导致子进程僵尸状态,那如果子进程不退出,而父进程先退出呢?
我们写一段这样的C语言代码来看看:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main()
{
    pid_t id = fork();
    if(id < 0) return 1;
    else if(id == 0)
    {
        // child
        while(1)
        {
    		printf("I am child ...\n");
            sleep(1);
	    }
    }
    else                                                    
    {
        // father
    	int cnt = 5;
        while(cnt)
        {
            printf("I am father, run times: %d\n", cnt--);
            sleep(1);
        }
        printf("I am father, dead: %d\n", cnt--);
        exit(2);
        // 回收操作
    }
 
    return 0;
}

在这里插入图片描述
当父进程退出时,是由bash回收的,但是子进程是要被父进程回收的,但是父进程先退出了,子进程要被领养,变成孤儿进程。
一般孤儿进程是要被1号进程领养,如果不领养就无法回收,导致内存泄漏。
那1号进程是谁呢?我们查一下:
在这里插入图片描述
这里一号进程叫做systemd,它其实就是操作系统。

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

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

相关文章

答题小程序源码系统:自带流量主广告位+视频激励广告 带完整的代码安装包以及搭建教程

随着互联网的迅速发展&#xff0c;各种应用程序层出不穷&#xff0c;而答题类小程序由于其独特的互动性和吸引力&#xff0c;成为了当前最热门的应用之一。答题小程序源码系统是一款基于微信小程序开发的源代码系统&#xff0c;它具有丰富的功能和灵活的定制性&#xff0c;可以…

视频号下载保姆级攻略:五大神级下载方法揭秘!

今天我要和大家聊聊一个非常有趣的话题&#xff0c;那就是如何下载视频号的视频。据我所知虽然很多人都知道视频号&#xff0c;但却不知道如何玩好视频号&#xff0c;以及怎么下载视频&#xff0c;我知道有些朋友可能对这个话题还不太了解&#xff0c;但是我相信&#xff0c;只…

决策树(公式推导+举例应用)

文章目录 引言决策树学习基本思路划分选择信息熵信息增益增益率&#xff08;C4.5&#xff09;基尼指数&#xff08;CART&#xff09; 剪枝处理预剪枝&#xff08;逐步构建决策树&#xff09;后剪枝&#xff08;先构建决策树再剪枝&#xff09; 连续值与缺失值处理连续值处理缺失…

【Spring Cloud】微服务架构演变及微服务架构介绍

文章目录 系统架构演变单体应用架构垂直应用架构分布式架构SOA 架构微服务架构 微服务架构介绍微服务架构的常见问题微服务架构的常见概念服务治理服务调用服务网关服务容错链路追踪 微服务架构的常见解决方案ServiceCombSpringCloudSpring Cloud Alibaba 总结 欢迎来到阿Q社区…

泥石流识别摄像头

泥石流是一种自然灾害&#xff0c;对人们的生命财产造成严重威胁。因此&#xff0c;如何及早发现和预警泥石流&#xff0c;成为了人们关注的焦点。为了提前发现泥石流并进行预警&#xff0c;科学家们设计了一种泥石流识别摄像头系统。 泥石流识别摄像头利用摄像头和图像识别技术…

C++从零基础到入门(2)—— (if、switch、for、while语句)

目录 一、if 条件语句 1.if 语句 2.if-else 语句 3.if-else if-else 语句 4.嵌套 if 语句 二、switch 语句 1.switch 语句基本语法 2.表示 switch 表达式的数据类型 &#xff08;1&#xff09;整型 &#xff08;2&#xff09;字符型 &#xff08;3&#xff09;枚举型…

RediSearch vs. Elasticsearch vs. solr

1. RediSearch vs. Elasticsearch RediSearch是一个分布式全文搜索和聚合引擎&#xff0c;作为Redis之上的一个模块构建。它使用户能够以极快的方式在Redis数据集上执行复杂的搜索查询。RediSearch的独特架构是用C编写的&#xff0c;从头开始构建在优化的数据结构上&#xff0…

Histone H3K4me2 Antibody, SNAP-Certified™ for CUTRUN

EpiCypher是一家为表观遗传学和染色质生物学研究提供高质量试剂和工具的专业制造商。EpiCypher推出的CUT&RUN级别的Histone H3K4me2 Antibody符合EpiCypher的批次特异性SNAP-CertifiedTM标准&#xff0c;在CUT&RUN中具有特异性和高效的靶点富集。通过SNAP-CUTANA™K-Me…

JVM基础(9)——新生代调优

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 学习必须往深处挖&…

【linux基础I/O(二)】文件系统讲解以及文件缓冲区的概念

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:Linux从入门到精通⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学更多操作系统知识   &#x1f51d;&#x1f51d; 基础I/O 1. 前言2. 理解C语言…

基于STM32的温室大棚环境检测及自动浇灌系统设计

需要全部资料请私信我&#xff01; 基于STM32的温室大棚环境检测及自动浇灌系统设计 一、绪论1.1 研究背景及意义1.2 研究内容1.3 功能设计 二、系统方案设计2.1 总体方案设计 三、系统硬件设计3.1 STM32单片机最小系统3.2 环境温度检测电路设计3.3 土壤湿度检测电路设计3.4 光…

MySQL的事务机制

一、事务机制简述 事务机制,避免写入直接操作数据文件&#xff1b;利用日志来实现间接写入&#xff0c;与事务有关的, redo日志与undo日志&#xff1b;sql语句操作记录复制到undo日志然后增删改查操作的结果会记录在redo日志&#xff0c;如果操作没有什么问题就把数据同步到数…

Linux 抓包还不会?这篇文章赶紧收藏!

前言 什么是TCPDUMP TCPdump&#xff0c;全称dump the traffic on a network&#xff0c;是一个运行在linux平台可以根据使用者需求对网络上传输的数据包进行捕获的抓包工具。 tcpdump可以支持的功能&#xff1a; 1、在Linux平台将网络中传输的数据包全部捕获过来进行分析 …

k8s-调度 13

调度器通过 kubernetes 的 watch 机制来发现集群中新创建且尚未被调度到 Node 上的 Pod。调度器会将发现的每一个未调度的 Pod 调度到一个合适的 Node 上来运行。 kube-scheduler 是 Kubernetes 集群的默认调度器&#xff0c;并且是集群控制面的一部分。 如果你真的希望或者有…

分享一款刚开源的音乐人声分离工具!无需联网!页面化操作!

前言 人声分离 是一项重要的音频处理技术&#xff0c;它可以将混合音频中的 人声和背景音乐 分离出来&#xff0c;为音频处理和后期制作提供了便利。 随着人声分离技术的发展&#xff0c;越来越多的开源工具被开发出来&#xff0c;为音频处理领域带来了新的发展机遇。小编之前…

C# 图解教程 第5版 —— 第21章 异步编程

文章目录 21.1 什么是 异步21.2 async/await 特性的结构21.3 什么是异步方法21.3.1 异步方法的控制流21.3.2 取消一个异步操作21.3.3 在调用方法中同步地等待任务21.3.4 在异步方法中异步地等待任务21.3.5 Task.Delay 方法 21.4 GUI 程序中的异步操作&#xff08;*&#xff09;…

倒L天线设计

λ/4单极子天线具有工作带宽较宽&#xff0c;辐射效率较高的优点&#xff0c;但是其体积较大&#xff0c;随着无线终端设备的体积越来越小&#xff0c;对天线空间的要求也越来越严格&#xff0c;于是为了适应终端设备的发展&#xff0c;单极子天线开始出现一些变形&#xff0c;…

基于Python实现身份证信息识别

目录 前言身份证信息识别的背景与意义自动识别身份证的需求 实现环境与工具准备Python编程语言OpenCV图像处理库Tesseract OCR引擎 身份证信息识别算法原理图像预处理步骤(图像裁剪、灰度化 、二值化、去噪)信息提取与解析 Python代码实现通过OCR提取身份证号码代码解析身份证信…

SQL-修改数据

&#x1f389;欢迎您来到我的MySQL基础复习专栏 ☆* o(≧▽≦)o *☆哈喽~我是小小恶斯法克&#x1f379; ✨博客主页&#xff1a;小小恶斯法克的博客 &#x1f388;该系列文章专栏&#xff1a;重拾MySQL &#x1f379;文章作者技术和水平很有限&#xff0c;如果文中出现错误&am…

计算机毕业设计 | SSM 校园线上订餐系统(附源码)

1&#xff0c; 概述 1.1 项目背景 传统的外卖方式就是打电话预定&#xff0c;然而&#xff0c;在这种方式中&#xff0c;顾客往往通过餐厅散发的传单来获取餐厅的相关信息&#xff0c;通过电话来传达自己的订单信息&#xff0c;餐厅方面通过电话接受订单后&#xff0c;一般通…