【Linux学习】深入了解Linux中进程状态及其转换

news2024/10/6 4:05:17

文章目录

  • 进程状态
    • 进程排队
    • 进程的状态(运行,阻塞,挂起)
      • 进程的七个状态
    • 孤儿进程


进程状态

进程 = task_struct + 可执行程序
进程不是一 直在运行的,可能在等待软硬件资源,比如scanf后,程序停止运行了,在等待用户输入。进程放在CPU上,也不是一直在运行的。时间片:进程在CPU上的时间,过了就会被拿下。

进程排队

先简单看看进程排队:
所谓的进程排队,一定是在等待某种资源,排队是进程的PCB(task_struct)在排队,而不是进程的可执行程序在排队。
一个task_struct(进程的PCB)可以被连入多种数据结构中, 在Linux内核中,每一个进程的PCB不是连入到单链表中的,而是连入到双链表的(队列可以用链表实现),这个结构和书本上学习的双链表结构一样的但用法不同而已,请看图解:
图一:
注释:如果像下图这样管理PCB的话(也就是每一个进程PCB中包含两个指针,但是这样只能连入一到一个数据结构中,如果想要连入到多种数据结构中,必须加指针,浪费空间,并且难维护),所以这种结构是不合适的。
在这里插入图片描述
图二:
注解:每一个进程的PCB中,包含特殊的结构体,然后将这个结构体指针放入双链表中进行管理,这样,就可以通过这个结构体指针找到进程的PCB,这个结构体指针也可以连入多种数据结构中。(利用struct listnode在对应进程的PCB中偏移量计算PCB的地址:(task_struct*)(&n-&((task_struct)0-> n)。如果PCB中存在很多个特殊的结构体,就可以将PCB连入到很多不用的数据结构中进行管理。
在这里插入图片描述

进程的状态(运行,阻塞,挂起)

所谓的状态,其实就是一个整型变量,在task_struct里面的一个整型变量:
在这里插入图片描述

状态决定了什么?
状态决定了下一步的后续动作。

一个CPU一个运行队列。
如简图:
在这里插入图片描述

  1. 运行状态:一个进程的PCB在CPU的运行队列上,不一定正在运行,把该进程的状态成为运行状态;

  2. 阻塞状态 :
    每一个设备为了操作系统能够管理。都会被先描述,后组织。将设备用一个结构体描述,结构体里面可能会包含设备类型,状态,以及当前设备的等待队列等。
    当一个进程在等待软硬件资源的时候,如果资源没有就绪,例如scanf时,操作系统会将该进程PCB从与逆行队列拿下来,状态由运行改为阻塞,连入到等待的资源提供的的等待队列中,等待资源;

  • 其中,状态的变迁引起的是PCB会被OS变迁到不同的队列中。
  1. 挂起状态:
    前提:当计算机资源已经很吃紧了;
    阻塞挂起:已经很吃紧了,但是有一些进程暂时不会被调度,操作系统会将该进程的代码与数据写入到外设(磁盘)中去,也就是腾空间。(磁盘有一个固定的区域,叫做swap分区,是用来给操作系统在资源紧张的时候,用来和磁盘进行数据的唤入与唤出)
    注意:进程的PCB不会被唤入(将数据拷贝到外设)唤出(将数据从外设唤入到内存)。
    创建一个进程的时候,先创建进程的对应的内核数据结构(PCB),再将代码与数据加载到内存(可以一部分一部分的加载,按需加载) 。

进程的七个状态

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): 意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠(阻塞状态)。crtl+c可以终止进程。
  • D磁盘休眠状态(Disk sleep),有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束。(阻塞状态)crtl+c不可以终止进程。
  • T停止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。
  • t(停止状态):在调试的时候可以看见。
  • Z(zombine):僵尸状态。
  • X死亡状态(dead):这个状态只是一个返回状态,你不会在任务列表里看到这个状态。

Linux进程状态转换图:
在这里插入图片描述

测试:使用指令

# ps ajx | head -1 && ps ajx | grep myprocess

测试代码1:

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<unistd.h>
  4 
  5 int main()
  6 {
  7   while(1)
  8   {
  9     printf("i am a proces id:%d\n",getpid());
 10     sleep(1);                                      
 11   }
 12   return 0;
 13 }

运行结果:
在这里插入图片描述

  • 问题:为什么我的代码在运行,但是确是S状态呢?
    答:因为CPU执行你的代码非常快,剩下的还执行了sleep函数,导致该进程大多时间处于sleep状态,只有很少量的时间被调度了一次,导致很难观察到运行状态。

测试代码2:

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

运行结果:
在这里插入图片描述

  • 问题:为什么我的代码将sleep注释掉了再运行,但是确还是S状态呢?
    代码中使用的printf函数,是要访问外设的,但是要访问这个设备,这个设备的资源不一定准备就绪了,但是CPU的执行速度很快,但是硬件的速度很慢,导致大部分时间也是在等待状态的。

测试代码3:

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

运行结果:
在这里插入图片描述

  • 为什么状态后有+呢,比如:S+
    后面带有+,说明是前台进程,没有代表为后台进程:
    例如:

指令(前台进程变为后台进程)

# ./myprocess &

可以将前台进程变为后台进程,后台进程使用键盘ctrl+c不能杀掉,只能用命令kill -9 杀掉;

例如:
测试代码:

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<unistd.h>
  4 
  5 int main()
  6 {
  7   while(1)
  8   {
  9     printf("i am a proces id:%d\n",getpid());
 10     sleep(1);                                      
 11   }
 12   return 0;
 13 }

在这里插入图片描述

T状态的测试:

测试代码:

 1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<unistd.h>
  4 
  5 int main()
  6 {
  7   while(1)
  8   {
  9     printf("i am a proces id:%d\n",getpid());
 10     sleep(1);                                      
 11   }
 12   return 0;
 13 }

运行结果:
T状态:让进程处于暂停状态。
在这里插入图片描述
t状态的测试:
当我们调试代码的时候,在每次单步执行的时候,程序会处于t状态(停止状态);

示例:
在这里插入图片描述

Z状态,僵尸状态:当一个进程退出后,但是该进程的状态需要自己维持住,供上层读取。也就是进程从退出到资源被清理的这个时间段,进程所处于的状态。

  • 当一个进程退出过后,代码和数据可以被直接释放,因为已经没有用了,但是,当前进程所对应的PCB,还不能被释放,里面还有记录进程的退出信息,是为了让系统或者其他进程能够读取到该进程的的退出信息进而执行下一步动作。只有该数据被拿走过后,这个进程才是真正的死亡状态。PCB才会被清理释放。
  • 如果父进程不读取子进程的退出信息,僵尸状态的进程,会一直存在,task_struct对象也会一直存在,都是要暂用内存的,会有内存泄漏。在Linux系统中,所有的进程退出后都是Z状态。只有被别人读取完成后,才会变为X状态。

测试代码:

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<unistd.h> 
  4
  5 int main()
  6 {
  7   pid_t id = fork();
  8   if(id==0)   
  9   {  
 10     int cnt = 5;                                                
 11     while(cnt) 
 12     {       
 13       printf("i is child  id:%d   pid:%d\n",getpid(),getppid());
 14       sleep(1);
 15       cnt--;
 16     }     
 17     exit(0);   //让子进程直接退出                                           
 18   }
 19   //father                                                     
 20   while(1)   
 21   {
 22     printf("i is father  id:%d   pid:%d\n",getpid(),getppid());
 23     sleep(1);
 24   }
 25   return 0;
 26 }

结果:5秒过后子进程状态变为Z(僵尸状态):因为进程退出后,退出信息你没有被读取;怎么读取后续文章再给出。
在这里插入图片描述

孤儿进程

如果一个进程的父进程已经退出,但是子进程还没有退出,这个子进程就被叫做孤儿进程。
这是孤儿进程会变为后台进程,只有不能ctrl+c杀掉,可以通过kill命令。

这个进程会被1号进程(操作系统)所领养;如果不被领养,就变成没有主的进程,当程序退出时,就会一直为僵尸进程,就会一直暂用资源(空间),所以孤儿进程会被1号进程领养,这样该进程的资源还可以被操作系统所回收。

测试代码:

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<unistd.h> 
  4 
  5 int main()
  6 {
  7   pid_t id = fork();
  8   if(id==0)
  9   {
 10     int cnt = 50;
 11     while(cnt)
 12     {
 13       printf("i is child  id:%d   pid:%d\n",getpid(),getppi    d());
 14       sleep(1);
 15       cnt--;
 16     }
 17     exit(0);   //让子进程直接退出
 18   }
 19   //father
 20   int cnt = 5;
 21   while(cnt)
 22   {
 23     printf("i is father  id:%d   pid:%d\n",getpid(),getppid    ());
 24     sleep(1);
 25     cnt--;
 26   }
 27   printf("父进程退出\n");
 28   return 0;
 29 } 

在这里插入图片描述

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

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

相关文章

【ARFoundation自学03】平面追踪可视化效果美化

对已检测到的平面默认的渲染效果显得有些生硬和突兀&#xff0c;有时我们需要更加友好、美观的的平面虚拟界面&#xff0c;这时就需要对已检测到的平面定制个性化的可视方案。为达到更好的视觉效果&#xff0c;处理的思路如下。 视觉效果前后对比&#xff01; &#xff08;本节…

从cuda到cudnn到pytorch

一、预配版本信息 1、cuda12.1.1 2、cudnn8.9.7 3、pytorch2.2.0 二、引用 深度学习之环境配置&#xff1a;【CUDA 12.1.1cuDNN 8.9.1】最新安装教程记录 -- 20240429_torch 1.12.0对应torchvision-CSDN博客 补充&#xff1a; cuda历史版本索引&#xff1a; NVIDIA Dev…

只需一行代码提高3DGS重建质量!随机初始化新SOTA

论文标题&#xff1a; Relaxing Accurate Initialization Constraint for 3D Gaussian Splatting 论文作者&#xff1a; Jaewoo Jung, Jisang Han, Honggyu An, Jiwon Kang, Seonghoon Park and Seungryong Kim 导读&#xff1a; 3DGS在新视角合成和三维重建方面展现了令人印…

医疗科技:UWB模块为智能医疗设备带来的变革

随着医疗科技的不断发展和人们健康意识的提高&#xff0c;智能医疗设备的应用越来越广泛。超宽带&#xff08;UWB&#xff09;技术作为一种新兴的定位技术&#xff0c;正在引领着智能医疗设备的变革。UWB模块作为UWB技术的核心组成部分&#xff0c;在智能医疗设备中发挥着越来越…

【开发 | 环境配置】解决 VSCode 编写 eBPF 程序找不到头文件

问题描述&#xff1a; 在使用 vscode 编写 eBPF 程序时&#xff0c;如果不做一些头文件定位的操作&#xff0c;默认情况下头文件总是带有“红色下划线”&#xff0c;并且大部分的变量不会有提示与补全。 在编写代码文件较小时&#xff08;或者功能需求小时&#xff09;并不会…

Java虚拟机揭秘-底层驱动力,性能保障!

Java虚拟机作为Java技术体系的核心组成部分&#xff0c;其重要性不言而喻。它不仅为Java提供了跨平台的能力&#xff0c;更是Java程序运行的基石。本文将为您深入解析Java虚拟机的工作原理、作用和应用场景&#xff0c;并通过生动的实例让您彻底理解这一关键技术。 一、Java虚拟…

可视化 | Seaborn中的矩阵图及示例

Seaborn是python提供的一个很棒的可视化库。它有几种类型的绘图&#xff0c;通过这些绘图&#xff0c;它提供了惊人的可视化能力。其中一些包括计数图&#xff0c;散点图&#xff0c;配对图&#xff0c;回归图&#xff0c;矩阵图等等。本文讨论了Seaborn中的矩阵图。 示例1&am…

《计算机网络微课堂》2-2 物理层下面的传输媒体

请大家注意&#xff0c;传输媒体不属于计算机网络体系结构的任何一层&#xff0c;如果非要将它添加到体系结构中&#xff0c;‍‍那只能将其放在物理层之下。 传输媒体可分为两类&#xff1a;一类是导引型传输媒体&#xff0c;‍‍另一类是非导引型传输媒体。 在导引型传输媒体…

操作系统总结4----死锁的处理策略总结

目录 2.4.2 死锁的处理策略-----预防死锁 &#xff08;1&#xff09;知识总览 &#xff08;2&#xff09;破环互斥条件 &#xff08;3&#xff09;破环不剥夺条件 &#xff08;4&#xff09;破环求情和保持条件 &#xff08;5&#xff09;破环循环等待条件 总结 2.4.3 死…

使用Python Tkinter创建GUI应用程序

大家好&#xff0c;当我们谈及使用Python Tkinter创建GUI应用程序时&#xff0c;我们涉及的不仅是技术和代码&#xff0c;更是关于创造力和用户体验的故事。Tkinter作为Python标准库中最常用的GUI工具包&#xff0c;提供了丰富的功能和灵活的接口&#xff0c;让开发者能够轻松地…

《计算机网络微课堂》2-3 传输方式

本节课我们介绍几种传输方式&#xff1a; 串行传输和并行传输同步传输和异步传输单工&#xff0c;半双工‍‍以及全双工通信 ​​ ‍ 串行 我们首先来看串行传输和并行传输&#xff0c;串行传输是指‍‍数据是一个比特依次发送的&#xff0c;因此在发送端和接收端之间‍‍只…

YOLOv10 论文学习

论文链接&#xff1a;https://arxiv.org/pdf/2405.14458 代码链接&#xff1a;https://github.com/THU-MIG/yolov10 解决了什么问题&#xff1f; 实时目标检测是计算机视觉领域的研究焦点&#xff0c;目的是以较低的延迟准确地预测图像中各物体的类别和坐标。它广泛应用于自动…

速看!!!24上软考-信息系统项目管理师真题回忆,考点已更新

整理了24上半年软考高级信息系统项目管理师的考试真题&#xff0c;软考一个批次一套题&#xff0c;现在都是机考&#xff0c;收集题目比较困难&#xff0c;希望能给个小小的赞支持一下。 注意&#xff1a;当天考试的宝子们可以对答案预估分数&#xff01;后面场次的宝子可以提…

基于jeecgboot-vue3的Flowable新建流程定义(一)

因为这个项目license问题无法开源&#xff0c;更多技术支持与服务请加入我的知识星球。 1、vue3版本因为流程分类是动态的&#xff0c;不再固定了&#xff0c;所以新建的时候需要选择建立哪种流程类型的流程 代码如下&#xff1a; <!-- 选择模型的流程类型对话框 -->&…

Spring Cloud学习笔记(Nacos):配置中心基础和代码样例

这是本人学习的总结&#xff0c;主要学习资料如下 - 马士兵教育 1、Overview2、样例2.1、Dependency2.2、配置文件的定位2.3、bootstrap.yml2.4、配置中心新增配置2.5、验证 1、Overview 配置中心用于管理配置项和配置文件&#xff0c;比如平时写的application.yml就是配置文件…

【MySQL】聊聊脏页flush的原理和控制策略

flush的时机 当更新一条SQL的时候&#xff0c;其实是先写undo日志&#xff0c;然后更新数据&#xff0c;二阶段写入redo 和 bin log。对于更新数据&#xff0c;其实是只修改了changer buffer中的数据&#xff0c;比如将name qxlxi, 但是磁盘数据页没有和内存页数据保持一致。…

删除指定目录

题目描述 我们定义一种目录结构字符串(类似Windows的 tree /f 的输出内容),用它来表达目录树的结构,如图所示: 目录结构字符串的输入仅含数字、字母和|-,其中:|- 表示子目录的层次符号;字母或数字组成目录名(字母大小写敏感)。 某一子目录挂接在其前面、最近的上一层…

【Linux系统编程】进程概念、进程排队、进程标识符、进程状态

目录 什么是进程&#xff1f; 浅谈进程排队 简述进程属性 进程属性之进程标识符 进程操作之进程创建 初识fork fork返回值 原理角度理解fork fork的应用 进程属性之进程状态 再谈进程排队 进程状态 运行状态 阻塞状态 挂起状态 Linux下的进程状态 “R”(运行状…

【Go专家编程——内存管理——垃圾回收】

垃圾回收 所谓的垃圾就上不在需要的内存块&#xff0c;垃圾如果不清理&#xff0c;这些内存块就没有办法再次被分配使用。在不支持垃圾回收的编程语言中&#xff0c;这些垃圾内存就上泄露的内存。 1. 垃圾回收算法 常见的垃圾回收算法有3种 引用计数&#xff1a;对每个对象…

SpringCloud的Config配置中心,为什么要分Server服务端和Client客户端?

SpringCloud的Config配置中心&#xff0c;为什么要分Server服务端和Client客户端&#xff1f; 在SpringCloud的Config配置中心中分了Server服务端和Client客户端&#xff0c;为什么需要这样分呢&#xff1f;它的思想是所有微服务的配置文件都放到git远程服务器上&#xff0c;让…