【Linux】进程状态僵尸进程和孤儿进程阻塞、挂起和运行

news2024/11/27 18:26:31

个人主页 : zxctscl
如有转载请先通知

文章目录

  • 1. 前言
  • 2. Linux的进程状态
    • 2.1 S状态
    • 2.2 R状态
    • 2.3 T/t状态
    • 2.4 D状态
  • 3. 僵尸进程和孤儿进程
    • 3.1 僵尸进程
    • 3.2 孤儿进程
  • 4. 进程的阻塞、挂起和运行
    • 4.1 运行
    • 4.2 阻塞状态
    • 4.3 挂起
    • 4.4 进程切换

1. 前言

上一篇博客中提到 【Linux】进程初步理解,这次继续来分享与进程有关的知识。

2. Linux的进程状态

Linux的进程状态就是struct task_struct内部的一个属性。
为了弄明白正在运行的进程是什么意思,我们需要知道进程的不同状态。一个进程可以有几个状态(在Linux内核里,进程有时候也叫做任务)。
下面的状态在kernel源代码里定义:

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):这个状态只是一个返回状态,你不会在任务列表里看到这个状态。

2.1 S状态

检测一下这些状态:
先写一个测试代码:

  1 #include<stdio.h>
  2 #include<sys/types.h>
  3 #include<unistd.h>
  4
  5 int main()
  6 {
  7
  8   while(1)
  9   {
 10     printf("I am a process,pid:%d\n",getpid());
 11   }
 12   return 0;
 13 }

运行代码:发现进程都是出于s状态:
在这里插入图片描述
printf在显示器上打的时候,根据冯诺依曼特体系结构,显示器是一个外设,所以CPU在跑当前程序时,要把数据写到内存中,然后刷新到外设上,但是不能保证,每一次打印的时候显示器都是就绪的。相比较CPU来讲,大部分时间这个进程都在等待设备资源是否就绪,如果资源不就绪,当前进程就一直出于S状态。

把代码在printf之前先休眠10秒:
在这里插入图片描述

此时发现进程一直出于S状态,可以直接ctrl+c把处于S状态的进程终止掉:
在这里插入图片描述
把S的这种状态叫做可中断睡眠,就是处于睡眠状态,依旧可以被外部信息随时打断。

2.2 R状态

那么把代码里面的printf给注释了:
在这里插入图片描述
此时进程都是R状态:
在这里插入图片描述

2.3 T/t状态

在kill命令中的19号命令,让进程暂停:

在这里插入图片描述
直接使用:

kill -19 pid

此时进程就处于T状态
在这里插入图片描述

在这里插入图片描述

要想让暂停的进程继续运行起来就用18号信号
在这里插入图片描述

此时进程又重新运行起来:
在这里插入图片描述
但是此时是在后台运行的,要想终止进程,只能使用kill -9。

在这里插入图片描述
暂停在之间调试的时候就已经用到了。

打开Makefile加-g选项

  1 testStatus:testStatus.c
  2   gcc -o $@ $^ -g
  3 .PHONY:clean
  4 clean:
  5   rm -f testStatus

在10行打一个断点,然后查看一下进程的运行状态:
在这里插入图片描述
遇到断点,进程就暂停下来。

2.4 D状态

D状态是Linux系统比较特有的状态。

D磁盘休眠状态(Disk sleep)有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束。

操作系统杀进程的时候时毫无类别的去杀,在写入关键数据的进程是不能被杀掉的,所以操作系统规定,凡是进程在就行数据IO,在等待外设,像磁盘资源时,把状态设为D状态。
D状态不可被杀,深度睡眠,不可中断睡眠,就是一种sleep状态。

消除D状态:1. 让进程自己醒来;2. 重启–断点

3. 僵尸进程和孤儿进程

3.1 僵尸进程

Linux中一个进程的退出,它会将自己的退出信息保留在自己的PCB中。如果不读取PCB中的进程退出消息,那么进程就一直不释放,一般会释放掉代码和数据,但PCB的内核数据结构是一直存在的,直到将来对进程进行等待;如果不等待,那么进程就一直出于僵尸状态。如果读取了这个进程的退出信息或者等待了,那么这个进程才会变成X,进而将进程的信息全部释放。

为了测试重新写一个父子进程代码:

  1 #include<stdio.h>
  2 #include<sys/types.h>
  3 #include<unistd.h>
  4
  5 int main()
  6 {
  7
  8   pid_t id=fork();
  9   if(id==0)
 10   {
 11     //child
 12     int cnt=5;
 13     while(cnt)
 14     {
 15       printf("I am a child,cnt:%d,pid:%d\n",cnt,getpid());
 16       sleep(1);
 17       cnt--;
 18     }
 19
 20   }
 21   else{
 22     //parent
 23     while(1)
 24     { printf("I am parent,running always,pid:%d\n",getpid());
 25       sleep(1);
 26       }
 27   }
 28   return 0;
 29 }

来看一下这个状态:
在这里插入图片描述

Z状态:已经运行完毕,但是需要维护自己的退出信息,在自己的进程task_struct会记录自己的退出信息,未来让父进程读取。
如果没有父进程读取,僵尸进程就会一直存在。
如果对僵尸进程一直不回收,就会引起内存泄漏问题,操作系统会调用waitpid来进行进程状态的改变,变为X,再由操作系统进行释放。

一个进程已经出于僵尸了,就不能kill,无法杀掉已经死掉的进程。
在这里插入图片描述

3.2 孤儿进程

如果一个进程在运行的时候,它的父进程先退出了,那么这个进程就是孤儿进程。

来代码看看:

  1 #include<stdio.h>
  2 #include<sys/types.h>
  3 #include<unistd.h>
  4
  5 int main()
  6 {
  7
  8   pid_t id=fork();
  9   if(id==0)
 10   {
 11     //child
 12     int cnt=5;
 13     while(cnt)
 14     {
 15       printf("I am a child,cnt:%d,pid:%d\n",cnt,getpid());
 16       sleep(1);
 17 
 18     }
 19 
 20   }
 21   else{
 22     //parent
 23     int cnt=5;
 24     while(cnt)
 25     { printf("I am parent,running always,pid:%d\n",getpid());
 26       sleep(1);
 27       cnt--;
 28     }
 29   }
 30  // while(1)
 31  // {
 32  //   sleep(1);
 33 //    printf("I am a process,pid:%d\n",getpid());
 34 //  }
 35   return 0;
 36 }

来看看现象:

在这里插入图片描述
父进程如果先退出,子进程就会变成孤儿进程, 而孤儿进程一般会被1号进程(OS本身)进行领养。
为了保证孤儿进程正常被回收,孤儿进程会被操作系统领养。

可以直接kill掉孤儿进程:
在这里插入图片描述

在之前在Linux上写的代码,怎么出来没有关系过僵尸呢?或者内存泄漏?
因为直接在命令行中启动的进程,它的父进程是bash,bash会自动回收新进程的Z。

4. 进程的阻塞、挂起和运行

在这里插入图片描述

在网上找的一张进程状态图:

在这里插入图片描述
终止状态就等价于Z状态和X状态。

4.1 运行

进程运行一般在CPU上运行。
进程=task_struct+进程的代码和数据

每一个进程都有task_struct,为了对当前所有的进程进行管理,用链表将它们链接起来。而每一个CPU都会有一个运行队列struct runqueue,要运行进程,就得将进程放入运行队列struct runqueue中。从此CPU要运行已经进程,就在运行队列的头部取出一个进程,然后把相关的代码和数据拿到CPU寄存器中,进而就可以调度这个进程了。
一般而言一个进程被放到CPU上这个进程状态就是R,但是大部分教材中说的是进程在运行队列中,该进程的状态就是R状态,这里意思就是进程已经准备好了,可以随时被调度。

在这里插入图片描述

一个进程一旦持有CPU,会一直只运行这个进程吗?
不会,进程基于时间片进行轮转调度的。(而Linux中并不是以这种方法调度的,在之后的博客中会提到,请多多关注。)
让多个进程以切换的方式进程调度,在一个时间段内同时得以推进代码,就叫做并发。

把任何时刻,都有多个进程在真的同时运行,叫做并行。

4.2 阻塞状态

在C语言中用过一个scanf,如果不往里面输入数据,会一直处于什么状态?

来看看代码:

  1 #include<stdio.h>
  2 #include<sys/types.h>
  3 #include<unistd.h>
  4 
  5 int main()
  6 {
  7
  8    int a=0;
  9
 10    scanf("%d",&a);
 11
 12    printf("a=%d\n",a);

在这里插入图片描述
阻塞状态就相当于S状态或者是D状态。

等待:等待键盘资源是否就绪,键盘上有没有被用户按下按键,按键数据交给进程:
在这里插入图片描述

操作系统是软硬件资源的管理者。
进程本身就是软件。
堆硬件的管理也是先描述在组织。

操作系统里面有一个结构体对设备就行管理,每一个结构体里面包含设备的状态,种类,还有指向其他设备的指针。
在这里插入图片描述
在等待说明进程并没有被调度,说明进程并不在运行队列中。

如果还有进程要等待键盘资源,就把对应的进程从运行队列放在等待队列里面。拿到对应的资源后,就回到运行队列里面,这个过程一般叫唤醒。
不是只有CPU才有运行队列,各种设备都有自己的等待队列。

阻塞和运行的状态变化,往往伴随进程PCB被连入到不同的队列中。

4.3 挂起

操作系统在运行进程的时候内存时比较吃紧的,一旦进程出于阻塞状态,那么就意味着当前进程不会被调度,这个进程的代码和数据就不会被访问,此时就会把这个进程的代码和数据唤出到磁盘上。那么曾经代码和数据占用的空间就空出来了,一旦获取到相应的资源,又会被唤起。
在这里插入图片描述

这个进程的PCB还在内存中,只是它的代码和数据在磁盘的swap分区,此时把这种状态叫做阻塞挂起。
这样操作系统就会更合理使用内存资源。

在用户层是感知不到的。
频繁的换入换出,会导致效率问题。这个是牺牲效率换取空间。

一般swap分区的大小不会太大,为了减少操作系统频繁的使用swap带来效率问题。

4.4 进程切换

CPU内部会有很多寄存器。
函数调用返回的临时变量,就用到了寄存器。

当一个进程被CPU调度的时候,CPU的寄存器中会保存当前进程的临时数据。如果这个进程的时间片到了,那么就会把这个进程从CPU上剥离下来,把下一个进程放上去。如果想要把这个进程恢复,就得保存上下文,然后CPU运行到这个进程又继续执行。
在这里插入图片描述

CPU内部的所有寄存器中的临时数据,叫做进程的上下文。

进程在切换,最重要的一件事就是:上下文数据的保护和恢复。

CPU内的寄存器:寄存器本身是硬件,具有数据的存储能力,CPU的寄存器硬件只有一套。
CPU内部的数据,可以有多套,有几个进程,就有几套和该进程对应的上下文数据。
所以寄存器!=寄存器内容

有问题请指出,大家一起进步!!!

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

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

相关文章

Redis: 持久化

文章目录 一、RDB持久化1、概念2、生成、载入RDB文件3、执行时机&#xff08;1&#xff09; 执行save命令&#xff08;2&#xff09;执行bgsave命令&#xff08;3&#xff09;Redis停机时&#xff08;4&#xff09;触发RDB条件 4、bgsave原理5、小结 二、AOF持久化1、概念2、AO…

Linux学习-网络UDP

网络 数据传输,数据共享 网络协议模型 OSI协议模型 应用层 实际发送的数据 表示层 发送的数据是否加密 会话层 是否建立会话连接 传输层 数据传输的方式&#xff08;数据报、流式&#…

C++STL(list类)

文章目录 1.list类的介绍2.list的基本用法2.1 基本用法2.2 迭代器失效2.3 reverse(逆置)2.3 sort(排序)2.4 unique(去重)2.5 splice(转移) 3.list的底层(模拟实现)3.1 list的3.2 修改链表问题3.3 完整代码 1.list类的介绍 list是可以在常数范围内在任意位置进行插入和删除的序列…

代码随想录阅读笔记-二叉树【将有序数组转换为二叉搜索树】

题目 将一个按照升序排列的有序数组&#xff0c;转换为一棵高度平衡二叉搜索树。 本题中&#xff0c;一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。 示例: 思路 做这道题目之前大家可以了解一下之前讲到的一些问题 从中序和后序遍历…

红豆开箱上手必读

什么是红豆&#xff1f; 红豆开源平台是由奇迹物联发布并主导维护的 LTE Cat1 物联网产品开发平台&#xff0c;它是基于 Cat1 蜂窝通信模组 AM430E 构建的技术开源平台。该平台的目标是帮助物联网行业从业者利用搭乐高模块化模式进行 Open CPU 开发&#xff0c;它为开发者提供…

C++:类与对象(一)

hello&#xff0c;各位小伙伴&#xff0c;本篇文章跟大家一起学习《C&#xff1a;类与对象&#xff08;一&#xff09;》&#xff0c;感谢大家对我上一篇的支持&#xff0c;如有什么问题&#xff0c;还请多多指教 &#xff01; 文章目录 面向对象和面向过程的区别1.类的引入2.…

2024年MathorCup妈妈杯数学建模思路C题思路解析+参考成品

1 赛题思路 (赛题出来以后第一时间在群内分享&#xff0c;点击下方群名片即可加群) 2 比赛日期和时间 报名截止时间&#xff1a;2024年4月11日&#xff08;周四&#xff09;12:00 比赛开始时间&#xff1a;2024年4月12日&#xff08;周五&#xff09;8:00 比赛结束时间&…

Hello 算法9:图

https://www.hello-algo.com/chapter_graph/graph/#911 图的基本概念 图由顶点和边组成&#xff0c;比起链表&#xff08;线性数据结构&#xff09;和树&#xff08;分治结构&#xff09;&#xff0c;图更自由也更复杂 方向性 在无向图中&#xff0c;边表示两个顶点之间的双…

苹果手机怎么查找对方手机位置?2招快速定位!

在现代社会中&#xff0c;智能手机已经成为我们生活中不可或缺的一部分。然而&#xff0c;随着手机的普及&#xff0c;我们也面临着一些问题&#xff0c;比如手机丢失或被盗。 在这种情况下&#xff0c;如何快速准确地找到手机的位置就显得尤为重要。苹果手机怎么查找对方手机…

PKI:构建数字安全基石的关键技术

在数字化时代&#xff0c;网络安全已成为我们日常生活和工作的重要组成部分。为了确保数据的完整性、机密性和身份的真实性&#xff0c;公钥基础设施&#xff08;Public Key Infrastructure&#xff0c;简称PKI&#xff09;技术应运而生&#xff0c;为构建数字安全基石提供了重…

面试算法-151-矩阵置零

题目 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,1,1],[1,0,1],[1,1,1]] 输出&#xff1a;[[1,0,1],[0,0,0],[1,0,1]] 解 class Solutio…

LangChain - 文档加载

文章目录 一、关于 检索二、文档加载器入门指南 三、CSV1、使用每个文档一行的 CSV 数据加载2、自定义 csv 解析和加载3、指定用于标识文档来源的列 四、文件目录 file_directory1、加载文件目录数据2、显示进度条 &#xff08;tqdm3、使用多线程 use_multithreading4、更改加载…

通用开发技能系列:Scrum、Kanban等敏捷管理策略

云原生学习路线导航页&#xff08;持续更新中&#xff09; 本文是 通用开发技能系列 文章&#xff0c;主要对编程通用技能 Scrum、Kanban等敏捷管理策略 进行学习 1.什么是敏捷开发 敏捷是一个描述软件开发方法的术语&#xff0c;它强调增量交付、团队协作、持续规划和持续学习…

如何使用生成式人工智能撰写关于新产品发布的文章?

利用生成式人工智能撰写新产品发布文章确实是一种既有创意又高效的内容生成方式。以下是如何做到这一点的指南&#xff0c;附带一些背景信息&#xff1a; • 背景&#xff1a;在撰写文章之前&#xff0c;收集有关您的新产品的信息。这包括产品的名称、类别、特点、优势、目标受…

git 常用命令和使用方法

作者简介&#xff1a; 一个平凡而乐于分享的小比特&#xff0c;中南民族大学通信工程专业研究生在读&#xff0c;研究方向无线联邦学习 擅长领域&#xff1a;驱动开发&#xff0c;嵌入式软件开发&#xff0c;BSP开发 作者主页&#xff1a;一个平凡而乐于分享的小比特的个人主页…

DJ的打碟是什么意思 FL Studio怎么制作打碟的效果

在如今的音乐文化中&#xff0c;DJ打碟已经成为一种重要的表演形式和音乐创作方式。但是&#xff0c;对于许多人来说&#xff0c;仍然会对DJ的打碟到底意味着什么存在疑惑&#xff0c;接下来给大家介绍DJ的打碟是什么意思&#xff0c;FL Studio怎么制作打碟的效果的具体内容。 …

Pentaho Data Integration(kettle)下载

Kettle已然是改了名了&#xff0c;新名字叫Pentaho Data Integration 网上常见的下载地址已经失效&#xff0c;被提示找不到Date Integration目录&#xff1a; https://sourceforge.net/projects/pentaho/files/Data%20Integration/ 点击页面上的pdf&#xff0c;下载文件后打…

基于单片机16路多路抢答器仿真系统设计

**单片机设计介绍&#xff0c;基于单片机16路多路抢答器仿真系统设计 文章目录 一 概要二、功能设计三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机16路多路抢答器仿真系统的设计概要主要涵盖硬件设计、软件编程以及功能实现等方面。以下是针对该设计的详细概…

ABAP 弹出输入框/弹出屏幕选择条件框

简单输入框 代码 DATA:TAB TYPE TABLE OF SVAL WITH HEADER LINE ,CODE TYPE C . TAB-TABNAME ZTAB_XX."表 TAB-FIELDNAME XXXX."字段 TAB-FIELDTEXT 条码扫描 ."说明 APPEND TAB. "弹出填写数据的框 CALL FUNCTION POPUP_GE…

mysql安装初始化(windows)

文章目录 一、下载二、 初始化数据库三、把mysql注册成服务 一、下载 https://downloads.mysql.com/archives/community/ 二、 初始化数据库 mysqld --initialize-insecure初始化完成后&#xff0c;可以开黑框运行数据库 mysqld --console三、把mysql注册成服务 mysqld -…