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

在这里插入图片描述

文章目录

  • 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,它其实就是操作系统。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于JavaWeb+BS架构+SpringBoot+Vue“共享书角”图书借还管理系统系统的设计和实现

基于JavaWebBS架构SpringBootVue“共享书角”图书借还管理系统系统的设计和实现 文末获取源码Lun文目录前言主要技术系统设计功能截图订阅经典源码专栏Java项目精品实战案例《500套》 源码获取 文末获取源码 Lun文目录 第1章 概 述 5 1.1 开发背景及研究意义 5 1.2 国内外研究…

MoE模型性能还能更上一层楼?一次QLoRA微调实践

Fine-Tuning Mixtral 8x7B with QLoRA&#xff1a;Enhancing Model Performance &#x1f680; 编者按&#xff1a;最近&#xff0c;混合专家(Mixture of Experts,MoE)这种模型设计策略展现出了卓越的语言理解能力&#xff0c;如何在此基础上进一步提升 MoE 模型的性能成为业界…

SPDK中常用的性能测试工具

本文主要介绍磁盘性能评估的方法&#xff0c;针对用户态驱动Kernel与SPDK中各种IO测试工具的使用方法做出总结。其中fio是一个常用的IO测试工具&#xff0c;可以运行在Linux、Windows等多种系统之上&#xff0c;可以用来测试本地磁盘、网络存储等的性能。为了和SPDK的fio工具相…

【RabbitMQ】RabbitMQ高级:如何保证消息可靠性

目录 概述异常捕获机制事务机制持久化存储机制发送端确认机制概述开启发布确认的方法单个发布确认批量发布确认异步发布确认 消费端确认机制消息限流消息幂等性处理 概述 前面学习了如何简单使用RabbitMQ&#xff0c;在实际使用RabbitMQ时&#xff0c;我们还需要考虑很多&…

Vue.js设计与实现阅读-2

Vue.js设计与实现阅读-2 1、前言2、框架设计的核心要素2、1 提升用户体验2、2 控制代码体积2、3 Tree-Shaking2、4 特性开关2、5 错误处理 1、前言 上一篇我们了解到了 命令式和声明式的区别&#xff0c;前者关注过程&#xff0c;后者关注结果了解了虚拟dom存在的意义&#x…

数据库SELECT语句

文章目录 一、检索数据二、排序检索三、过滤数据四、数据过滤4.1 组合WHERE子句1. AND操作符2. OR操作符3. 计算次序 4.2 IN操作符4.3 NOT操作符 五、用通配符过滤LIKE操作符1. 百分号&#xff08;%&#xff09;通配符2. 下划线&#xff08;_&#xff09;通配符 使用通配符的技…

盈利之道:下单前的必问之问

投资者在过去的交易经历中&#xff0c;通常都会面临所谓的“交易低谷”。交易低谷是指在交易过程中难以实现盈利或可能导致进一步亏损的阶段。这种面临损失或没有盈利的时期可能发生在任何人身上&#xff0c;无论是由于市场变化、投资者策略调整还是其他原因。为了应对这种情况…

CSS基础方法——引入方式、属性、基础选择器

CSS 主要用于设置 HTML 页面中的文本样式&#xff08;字体、大小、颜色、对齐方式……&#xff09;、图片样式&#xff08;宽高、边框样式、边距……&#xff09;以及版面的布局和外观显示样式。 1、CSS引入方式 行内样式 写在标签中&#xff0c;通常不使用&#xff0c;只做…

优惠券兑换码生成需求——事务同步回调问题分析

前段时间收到一个优惠券兑换码的需求&#xff1a;管理后台针对一个优惠券发起批量生成兑换码&#xff0c;这些兑换码可以导出分发到各个合作渠道&#xff08;比如&#xff1a;抖音、京东等&#xff09;&#xff0c;用户通过这些渠道获取到兑换码之后&#xff0c;再登录到我司研…

提升测试效率,轻松并行运行测试——探秘Pytest插件pytest-xdist

在软件开发中&#xff0c;测试是确保代码质量的重要一环。然而&#xff0c;随着项目规模的增大&#xff0c;测试用例的数量也随之增多&#xff0c;测试的执行时间可能成为一个瓶颈。为了解决这个问题&#xff0c;Pytest提供了丰富的插件生态系统&#xff0c;其中 pytest-xdist …

黑群晖6.x 7.x ABB Active Backup for Business 套件激活方法

注意事项&#xff1a; 要先下载安装好Active Backup for Business套件再操作。SN码在【控制面板】 - 【信息中心】 -【产品序列号】。建议复制到记事本内修改内容。群晖的https是默认的5001端口&#xff0c;如果你的https端口号换过请自行修改&#xff1a;5001 为当前的端口号…

spacedesk 变成黑白的分析

测试发现只要调整时间到2024 就会出现黑白而且是建立连接是才检测的&#xff0c;那么应该存在于R3部分的可能性大 IDA分析找到2024

[论文阅读]4DRadarSLAM: A 4D Imaging Radar SLAM System for Large-scale Environments

目录 1.摘要和引言&#xff1a; 2. 系统框架&#xff1a; 2.1 前端&#xff1a; 2.2 回环检测&#xff1a; 2.3 后端&#xff1a; 3.实验和分析&#xff1a; 4.结论 1.摘要和引言&#xff1a; 这篇论文介绍了一种名为“4DRadarSLAM”的新型4D成像雷达SLAM系统&#xff0…

RT-DETR优化:UNetv2多层次特征融合模块结合DualConv、GSConv

🚀🚀🚀本文改进:多层次特征融合(SDI)结合DualConv、GSConv模块等实现二次创新 🚀🚀🚀SDI 亲测在多个数据集能够实现涨点,同样适用于小目标检测 🚀🚀🚀RT-DETR改进创新专栏:http://t.csdnimg.cn/vuQTz 学姐带你学习YOLOv8,从入门到创新,轻轻松松搞定…

Vue、uniApp、微信小程序、Html5等实现数缓存

此文章带你实现前端缓存&#xff0c;利用时间戳封装一个类似于Redis可以添加过期时间的缓存工具 不仅可以实现对缓存数据设置过期时间&#xff0c;还可以自定义是否需要对缓存数据进行加密处理 工具介绍说明 对缓存数据进行非对称加密处理 对必要数据进行缓存&#xff0c;并…

太平洋产险海南分公司:春季爱车保养,就看这几点!

一年之计在于春&#xff0c;春天不仅是万物复苏的好时节&#xff0c;也是一年中非常适合汽车养护的季节。 刚刚过去的春节&#xff0c;汽车的使用频率大大增加&#xff0c;很多车主都准备对爱车进行一次全面保养。加上立春过后&#xff0c;天气渐暖&#xff0c;许多车主也计划开…

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

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

搭建算法日志自检小系统

&#x1f952; 前言 目前演示的是一个工具&#xff0c;但如此&#xff0c;未来完成有潜力可以演变为一整套系统。 &#x1f451;现场人员自检失败表计点位教程V2.0 NOTE: 如果没有“logfiles-meter-tool“目录的请联系我们进行提供&#xff01; &#x1f447; 进入<dist>…

使用AutoDL云计算平台训练并测试Pytorch版本NeRF代码

文章目录 前言一、数据集及代码获取二、租用并设置服务器三、Pycharm远程开发四、训练并测试代码 前言 因为第一次在云服务器上跑代码&#xff0c;所以在这里记录一下。 一、数据集及代码获取 nerf-pytorch项目是 NeRF 的忠实 PyTorch 实现&#xff0c;它在运行速度提高 1.3 倍…

docker 利用特权模式逃逸并拿下主机

docker 利用特权模式逃逸并拿下主机 在溯源反制过程中&#xff0c;会经常遇到一些有趣的玩法&#xff0c;这里给大家分享一种docker在特权模式下逃逸&#xff0c;并拿下主机权限的玩法。 前言 在一次溯源反制过程中&#xff0c;发现了一个主机&#xff0c;经过资产收集之后&…