Linux:进程状态

 目录

1.Linux内核关于进程状态的源代码 

2. 运行状态

3. 阻塞状态

4. 挂起

5.Linux中的进程状态

5.1 睡眠状态

5.2 暂停状态 

5.3 僵尸进程与孤儿进程


我们在学习进程状态时,老师只是简单的让我们记住下面这张图 

1.教材中进程操作系统的进程状态

那么这些进程状态到底是什么意思呢?本篇文章将具体讲解上面教材中提到的进程状态在linux中的体现。

1.Linux内核关于进程状态的源代码 

为了弄明白正在运行的进程是什么意思,我们需要知道进程的不同状态。一个进程可以有几个状态(在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): 意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠(interruptible sleep))。
  • D磁盘休眠状态(Disk sleep)有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束。
  • T停止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。
  • X死亡状态(dead):这个状态只是一个返回状态,你不会在任务列表里看到这个状态,这个进程即将被销毁。

进程状态,就是PCB中的一个字段,就是结构体中的一个变量,这些进程状态类型就是通过#define 出的宏常量

所谓状态变化,就是在PCB(Linux叫 task_struct)中修改代表进程状态变量的值,然后将PCB链入不同的队列中,比如运行队列,等待对列等。所以说所有的过程,都只与进程的PCB有关,与代码和数据无关。

2. 运行状态

创建一个进程就是将代码和数据拷贝进内存,然后为这个进程创建PCB,PCB内有指针指向要执行的代码。所以进程 = 内核创建的PCB + 代码和数据。

每个CPU都有一个运行队列,通过双向链表将就绪的PCB连接起来,只是这个进程的PCB在运行队列中,或者正在被CPU执行,都是运行状态。

教材中的就绪和执行在Linux中统称为运行状态:R运行状态(running)。

查看运行状态:

这里写一个死循环让代码一直运行: 

通过 ps axj 来查看所有的进程通过grep筛选名称,head -1显示第一行:

可以看到STAT就是进程状态,R+。下面那个进程是grep指令的进程。+号的意思是前台进程,这时命令行不会执行其他命令,可以输入ctrl+c终止程序,后台进程在 ./文件名 后加&即可。

后台进程不能通过ctrl+c 关闭,前台可以执行其他命令,只能通过kill -9 pid 杀掉这个进程。

3. 阻塞状态

我们代码中一定会或多或少访问系统中的软件和硬件资源,比如磁盘,键盘,网卡,如果程序要求我们输入,但是我们键盘上不输入,也就是要访问的资源没有就绪,所以代码就无法向后进行,这时就会出行阻塞状态。

 我们知道操作系统并不是直接管理软件和硬件,而是管理的它们的信息,通过先描述,创建关于软件(进程)和硬件的信息的结构体,通过链表组织起来,即先描述,再组织,可以更好的管理相关的设备。

当出现访问设备出现阻塞时,我们就需要把进程的PCB链接到要访问设备的等待队列中,这里要注意的是:不是PCB不是仅仅存在一个队列中,他可能同时存在多个队列中,这是因为PCB的内部存在指针结构体,它是指向下一个和上一个PCB内部的指针结构体,而这样的结构体有多个。

注意:

操作系统中,会存在非常多的队列,运行队列,等待硬件的设备等待队列等。一个PCB可以存在多个对类中,所有系统内的进程是用双链表链接起来的

查看阻塞状态:

 通过scanf 让进程访问键盘:

 我们不输入数据,这个进程就会一直处于阻塞状态:

Linux下显示为S+,+表示前台进程。

4. 挂起

如果一个进程当前被阻塞了,注定了,这个进程在它所等待的资源没有就绪的时候,该进程是无法被调度的。如果此时,恰好OS内的内存资源已经严重不足了,怎么办??操作系统OS会将内存数据进行置换到外设磁盘上,针对所有阻塞进程,全部都由OS自动执行!这是进程状态就是挂起。

不用担心慢的问题,因为这个是必然的,现在主要关心的是让OS继续执行下去。

磁盘中会有一块swap分区,OS内的数据会被交换到这里,如果当进程被OS调度,曾经被置换出去的进程代码和数据,又要重新被加载到内存中。

这个状态一般是不容易看到的,要OS内存资源不足时才能看到,这里就不做展示了。

5.Linux中的进程状态

5.1 睡眠状态

  • S睡眠状态(sleeping):休眠状态,浅度睡眠,可以被终止,会对外界信号做出反应。
  • D磁盘休眠状态(Disk sleep):休眠状态,深度睡眠

上面两个都是阻塞状态。S状态上面已经讲过了,这里讲一下D状态。

D磁盘休眠状态是专门为磁盘设计的一种状态。我们要知道,如果在内存资源不足的情况下,操作系统会通过杀掉进程,节约资源的。当一个进程的进程状态处在D状态时,表示这个进程不可以被杀掉,不管是通过kill命令还是OS,都是不行的。

这是为什么呢?因为当进程要向磁盘中写入数据时,会将数据交给磁盘,让磁盘写入,然后等待磁盘返回是否写入成功的信息,如果这时进程被杀掉,且磁盘中途写入数据失败,磁盘这时要把错误信息返回给进程,但找不到进程,磁盘会将数据丢掉,会造成数据丢失。为了防止这种状况出现,专门设计出了D状态,进程不能被杀掉,只能等待D状态结束。

我们用户一般是看不到D状态的,如果我们看到D状态,几乎计算机快要挂掉,因为还会有其他的进程等待访问磁盘。

5.2 暂停状态 

  • T停止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。

我们在Linux状态中看到两个T,T/t,其实内核中两个都是T,那它们两个有什么区别呢?

我们先来了解一下kill 命令的显示信号,使用kill -l 查看

我们现在用到是下面三个: 

  • kill -9 是杀掉一个进程
  • kill -18是让一个进程继续
  • kill -19是让进程暂停

我们写一个while(1);死循环然后运行

这里T是普通的stopping 状态,使用kill -19强制进程暂停。可以发现kill -18 后进程成为后台运行状态,结束的话要用kill -9 杀掉进程。

当我们使用gdp对进程调试追踪,进程遇到断点暂停时,这种T是(tracing stop)追踪暂停。它们都会显示T。

以上S,D,T状态在教材中统称为阻塞状态。

5.3 僵尸进程与孤儿进程

  • Z (zombie)僵尸进程,这个进程已经执行完任务,但PCB还没有被释放。

进程=内核PCB+进程的代码和数据,都要占据内存空间,进程退出的核心工作之一就是将PCB和自己的代码和数据释放掉!

为什么我们要创建一个进程??一定是因为父进程要子进程要完成某种任务!父进程怎么知道进程把任务完成的怎么样?所以进程在退出的时候,要有一些退出信息,表明自己把任务完成的怎么样!

当一个进程在退出的时候,退出信息会由OS写入到当前退出进程的PCB中可以允许进程的代码和数据空间被释放但是不能允许进程的PCB被立即释放!!要让OS或者父进程,读取进程的PCB中的退出信息,得知子进程退出的原因!

进程退出了,但是还没有被父进程或者OS读取,OS必须维护这个退出进程的PCB结构!!此时,这个进程基本上已经算退出了,此时进程状态为:Z,僵尸状态!

如果一个进程Z状态了,但是父进程就是不回收它,PCB就要一直存在,父进程或者OS读取之后,PCB状态先被改成X状态,表示可以释放了,才会被OS释放。

如果我们一直不会回收,会造成内存泄漏,PCB一直占用系统资源。

僵尸进程查看:

int main()    
{    
    pid_t id = fork();    
    if(id<0)    
        return 1;    
    if(id==0)    
    {    
        //子进程    
        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     
    {    
        //父进程    
        while(1)    
        {    
            printf("I am father,running any time!\n");    
            sleep(1);    
        }    
        //没有回收子进程,子进程会一直为Z状态    
        //回收操作以后文章讲解
    }                                                                      
    return 0;    
}     

因为父进程是死循环,不能停下,不能回收子进程,子进程就会出现Z 僵尸状态,称为僵尸进程。

孤儿进程 

上面程序是子进程先运行结束,而父进程先运行结束后出现什么呢?

子进程的父进程先退出了,子进程要被领养,变成孤儿进程。

int main()                                                           
{    
    pid_t id = fork();    
    if(id<0)    
        return 1;    
    if(id==0)    
    {    
        //子进程    
        while(1)    
        {    
            printf("I am child...\n");    
            sleep(1);    
        }    
    }    
    else    
    {    
        //父进程    
        int cnt = 5;    
        while(cnt)    
        {    
            printf("I am father,run times:%d\n",cnt--);    
            sleep(1);    
        }    
        printf("I am father, dead:%d\n",cnt--);    
        //父进程先退出,子进程还在运行    
        //bash会回收掉父进程    
        //不会管孙子进程    
    }    
    return 0;    
}   

可以发现子进程的PPID变成了1,被1进程领养,变成孤儿进程。那1号进程是什么呢?

我们可以使用top指令正在运行的进程的相关信息:

1号进程 systemd 就是操作系统。为什么要被领养呢,因为要防止孤儿进程没有进程接收返回值,导致PCB无法释放,造成内存泄漏。

本篇结束!

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

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

相关文章

四、shell - 字符串

目录 1、单引号 2、双引号 3、拼接字符串 3.1 使用双引号拼接 3.2 使用单引号拼接 4、获取字符串长度 ​​​​​​​5、提取子字符串 ​​​​​​​6、查找子字符串 ​​​​​​​字符串是shell编程中最常用最有用的数据类型&#xff08;除了数字和字符串&#xff0…

大模型的RPA应用 | 代理流程自动化(APA),开启智能自动化新纪元

随着技术创新的持续推进&#xff0c;自动化技术已经变得至关重要&#xff0c;成为驱动企业和社会向前发展的核心动力。在自动化的里程碑中&#xff0c;机器人流程自动化&#xff08;RPA&#xff09;已经有效地将简单、重复且规则性的任务自动化。可是随着对处理更为复杂、多变且…

“最甜港姐”走的与众不同之路

网络图片 媒体最新报道&#xff0c;她被誉为“最甜港姐”&#xff0c;曾是TVB炙手可热的当红花旦&#xff0c;却在最当红的时候选择急流勇退。 她不是退圈去相夫教子&#xff0c;而是读书深造&#xff0c;成为一名专业律师。 前不久&#xff0c;又有消息传出&#xff0c;明年…

VUE2+THREE.JS辉光设定和解决辉光导致背景变暗的问题

THREE.JS辉光设定和解决辉光导致背景变暗的问题 THREE.JS 辉光设定THREE.JS 辉光导致背景变暗的问题1.设定背景图片2.初始化辉光3. animate 一直渲染辉光 THREE.JS 辉光设定 给我的设计好的fbx模型,已经设定好了模型发光材质,所以直接添加辉光效果,就可以自动发光 blender模型生…

Docker 安装部署 Sentinel Dashboard

1、下载 jar 包 官方 jar 包下载地址&#xff1a;https://github.com/alibaba/Sentinel/releases 或者点击 链接 直接跳转到下载页 进入链接下载你需要的版本 下载完毕&#xff08;我这里统一放在一个sentinel目录内&#xff09; 2、编写 Dockerfile 文件&#xff08;这里我不…

求臻医学满分通过EMQN室间质评,检测实力再获国际权威机构认可

近日&#xff0c;欧洲分子基因诊断质量联盟&#xff08;European Molecular Genetics Quality Network&#xff0c;EMQN&#xff09;公布了2023年Oncogene panel 项目能力验证考核结果&#xff0c;求臻医学旗下北京和杭州检验实验室&#xff0c;使用自主研发的ChosenOne大Panel…

Apache DolphinScheduler 开源之夏采访:苏国伟的开源之旅

个人介绍 大家好&#xff0c;我是苏国伟&#xff0c;来自西安电子科技大学软件工程专业。我在实验室中主要从事数据集成等方面的工作。除了编程&#xff0c;我还热衷于踢足球、观看球赛和健身&#xff0c;这些爱好让我的生活更加丰富多彩。 开源之路 我最初是在本科的分布式…

【Linux基础开发工具】yum生态vim的配置与使用

目录 前言 1. Linux 软件包管理器 yum 1.1 什么是yum 1.2 快速上手yum 1.3 yum生态 2. Linux编辑器vim 2.1 vim的模式 2.2 vim使用技巧 3. vim编辑器辅助功能配置 3.1 配置 3.2 用户sudo权限配置 总结 前言 Linux基础指令与权限之后&#xff0c;Linux系统开发工具的使用…

美林防火建材——朱林甫 坚韧与创新:美林传奇

在这个变幻莫测的时代&#xff0c;有一些创业者凭借着对行业的深刻理解和对未来的敏锐洞察&#xff0c;不仅在商海中乘风破浪&#xff0c;更是引领了整个行业的发展。今天&#xff0c;我们要讲述的&#xff0c;就是一位这样的创业者——来自浙江嘉善的朱总&#xff0c;他创立的…

初始Redis(入门篇)

目录 什么是Redis Redis特性 速度快 丰富的功能 客户端语言多 持久化 主从复制 Redis可以做什么 缓存 排行榜系统 计数器应用 消息队列系统 Redis安装 centos7安装 Redis重要文件 Redis的使用 Redis通用命令 set get keys exists del expire 什么是Redi…

生成式AI与预测式AI的主要区别与实际应用

近年来&#xff0c;预测式人工智能&#xff08;Predictive AI&#xff09;通过先进的推荐算法、风险评估模型、以及欺诈检测工具&#xff0c;一直在推高着该领域公司的投资回报率。然而&#xff0c;今年初突然杀出的生成式人工智能&#xff08;Generative AI&#xff09;突然成…

如何绕过某讯手游保护系统并从内存中获取Unity3D引擎的Dll文件

​ 某讯的手游保护系统用的都是一套&#xff0c;在其官宣的手游加固功能中有一项宣传是对比较热门的Unity3d引擎的手游保护方案&#xff0c;其中对Dll文件的保护介绍如下&#xff0c; “Dll加固混淆针对Unity游戏&#xff0c;对Dll模块的变量名、函数名、类名进行加密混淆处理&…

Android中添加C或C++代码

1、创建cpp目录&#xff0c;用于存放C和C代码。 2、创建CMake构建脚本CMakeLists.txt文件&#xff0c;将其放在cpp目录中。 # Sets the minimum version of CMake required to build the native library. cmake_minimum_required(VERSION 3.22.1)# Declares and names the pro…

单宁对葡萄酒可饮用性和陈酿潜力会有影响吗?

当在酿酒过程中葡萄酒中的单宁过量时&#xff0c;酿酒师可以使用白蛋白、酪蛋白和明胶等各种细化剂&#xff0c;这些药物可以与单宁分子结合&#xff0c;并将其作为沉淀物沉淀出来。随着葡萄酒的老化&#xff0c;单宁将形成长长的聚合链&#xff0c;氧气可以与单宁分子结合&…

数据挖掘实战-基于word2vec的短文本情感分析(文末送书)

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

【PPT模板合集】关于自制内容的PPT模板合集,包括原创的PPT及改良内容的PPT,适合科研/比赛/工作

【PPT模板合集】关于自制内容的PPT模板合集&#xff0c;包括原创的PPT及改良内容的PPT&#xff0c;适合科研/比赛/工作 零、前言一、校园层面的PPT模板1.1 各种毕业答辩1.2 夏令营答辩1.3 奖学金答辩1.4 比赛/项目答辩 二、学术层面的PPT模板2.1 学术汇报2.2 会议海报类型 三、…

使用VScode通过内网穿透在公网环境下远程连接进行开发

文章目录 前言1、安装OpenSSH2、vscode配置ssh3. 局域网测试连接远程服务器4. 公网远程连接4.1 ubuntu安装cpolar内网穿透4.2 创建隧道映射4.3 测试公网远程连接 5. 配置固定TCP端口地址5.1 保留一个固定TCP端口地址5.2 配置固定TCP端口地址5.3 测试固定公网地址远程 前言 远程…

网站监控有什么作用?

科技改变生活&#xff0c;科技的发展让我们的生活越来越精彩丰富&#xff0c;数据中心机房监控系统也可以称为“自我监控系统”&#xff0c;主要是针对机房所有的设备及环境进行集中监控和管理的&#xff0c;其监控对象构成机房的各个子系统&#xff1a;动力系统、环境系统、消…

SpringBoot+Redis获取电脑信息

获取电脑信息 测试 System.getProperties(); System: 是Java中的一个内置类&#xff0c;用于提供与系统相关的功能和信息。这个类中包含了一些静态方法和常量&#xff0c;可以让您方便地访问和操作系统级别的资源。 getProperties(): 是一个静态方法&#xff0c;它返回一个表示…

学习笔记小结

redis-cluster集群 redis3.0引入的分布式存储方案 集群由多个node节点组成&#xff0c;redis数据分布在这些节点当中。 在集群之中分为主节点和从节点 集群模式当中&#xff0c;主从一一对应&#xff0c;数据的写入和读取与主从模式一样&#xff0c;主负责写&#xff0c;从…
最新文章