Linux进程状态

简介: Linux进程状态

前言

       如果大家学习过操作系统,那么对于以上这张图会比较熟悉,但是不同的操作系统实际上对于进程状态的定义也是不同的。对于Linux操作系统我们可以大致分为三个状态:运行状态、阻塞状态、挂起状态。

       通俗的理解,进程状态就是PCB中的一个字段,就是PCB中的一个变量,int status,我们通过改变PCB中的status变量,就相当于改变了对应的状态。后续再将PCB链入不同的队列中就相当于进程状态的变化。

      请记住:进程状态变化的本质就是1、改变PCB中的status值。2、将PCB链入不同的队列中。

什么是运行状态?

先了解一个概念—每一个CPU在系统层面都会维护一个运行队列,而只要在运行队列中的进程,状态都是运行状态。运行队列中包涵着众多的属性,其中主要管理进程的实际上就是一个PCB类型的结构体链表,通过链接每一个进程的PCB以此来确定进程为运行状态。运行状态实际上就对应以及包含了传统进程状态中的创建状态、就绪状态、执行状态

什么是阻塞状态?

操作系统管理着诸多的资源,我们一定会或多或少的访问系统中的某些资源,这些资源包括系统软件、驱动程序、硬件等等。我们可以通过先描述,在组织,来构建对应设备的结构体。接着通过在系统中用一个设备列表来将这些设备都链接起来进行管理,当然这些结构体中肯定是包含对应的状态、设备描述符、属性以及最重要的进程等待队列等等。

阻塞实际上就是进程等待某种资源就绪的过程,在这里我们就是将PCB链入等待队列中,当某个资源被占用,其它进程也要使用,那么其它进程需要链入对应资源的等待队列中,并且将对应的字段改为阻塞状态,以此等待资源。在等待到资源后,就可以将对应进程的字段改回运行状态,然后链回到运行状态的队列中。这样看来,不同的资源是不是都有不同的等待队列呢?是的,也就是说操作系统中会有很多的队列,运行队列、等待硬件的设备的等待队列等。

什么是挂起状态?

————————————————

   磁盘当中存在着一个分区-swap分区(大概为内存的大小或者两倍),OS中的数据会交换到这里。当内存足够时且进程被OS调度时,被置换出去的内存和数据将会从这里被重新加载进来。如下图:

Linux中对于进程状态的详细理解

进程状态源码

R运行状态(running) : 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里。

S睡眠状态(sleeping): 意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠(interruptible sleep))。

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

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

X死亡状态(dead):这个状态只是一个返回状态,你不会在任务列表里看到这个状态。

前台进程与后台进程:

(./可执行程序) 默认为前台进程,通常表现为状态+ 此时可以通过Ctrl+c强行终止

(./可执行程序 &)为后台进程,通常表现为状态 此时不能通过Ctrl+c强行终止,需用 kill -9 杀死进程

查询进程状态

while :; do ps ajx | head -1 && ps ajx | grep 执行程序名 | grep -v "grep"; sleep 1; echo "*******************************"; done

S睡眠状态(sleeping)

实际上也就是上面提到的阻塞状态,当然根据以上等待资源的概念,那么我们就下来的D、T、t也属于阻塞状态!在Linux叫做休眠状态,也被叫做浅度睡眠,它可以被终止。为什么叫浅度睡眠呢?因为浅度会对外部的信号做出响应。比如可以被Ctrl+c强行终止。

D磁盘休眠状态(Disk sleep)

  也叫休眠状态,只不过也叫做深度睡眠。它是专门针对磁盘来设计的。在了解D状态前我们先了解一个概念—Linux在实在没办法的时候会通过杀掉进程来节省资源。那么,假设现在OS就处于这个情况,而此时有个进程正在向磁盘写入数据,如果此时如果刚刚好这个进程被OS杀掉了,那这个时候就出现问题了。因此,D状态就是针对这种情况,这是为了防止当进程向磁盘写入关键数据时而被杀掉,对于D状态的进程是无法被杀掉的。说一个题外话,如果我们查看到了D状态说明计算机离宕机不远了(#^.^#)

T停止状态(stopped)

在了解这个状态前我们先理解一下信号的概念,输入以下命令可查看信号:

kill -l


  怎么理解这些信号呢?我们进程用的杀死进程的命令,kill -9 就对应了其中一个信号,对这些信号量的理解,可以理解成用宏定义的数字。对于命令可以应用对应的信号名,也可以用对应的数字。


我们要看到停止状态,可以用kill -SIGSTOP pid 或者kill -19 pid 来停止对应的进程。如下图:


那么我们为什么要暂停进程呢?因为在进程访问软件资源的时候,可能暂时不让进程进行访问,就将进程设置为stop。


t追踪停止状态(tracing stop)

       debug程序的时候,追踪程序,遇到断点,进程就暂停了!此时,会显示出t状态。如下:

X死亡状态(dead)

   就是字面所描述,进程死亡。这个状态也很难见到,因为进程死亡了,进程会释放资源,但是难以查看到。

Z僵尸状态(zombie)

什么是僵尸状态?

       我们都知道进程=内核PCB+进程代码和数据。进程退出的核心工作之一就是将PCB和自己的代码和数据释放掉。进程在退出的时候要有一些退出信息,以表明自己把任务完成的怎么样。因此,当一个进程退出的时候,退出信息会有OS写入到当前退出进程的PCB中,可以允许代码和数据空间被释放掉,但是不能允许进程的PCB被立即释放!这是为了要让OS或者父进程读取退出进程的PCB中的退出信息,得知子进程的退出原因!如果进程退出了,但是还没被父进程或者OS读取,OS必须维护这个进程的PCB结构!

       此时,这个进程状态被称为Z僵尸状态(zombie)。父进程或者OS读取后,PCB状态才会被改成X状态,才会释放。如果一个进程Z状态了,但是父进程就是不回收他,PCB会一直存在,如果我们不及时回收,会造成内存泄漏!

       僵尸状态(Zombies)是一个比较特殊的状态。当进程退出并且父进程没有读取到子进程退出的返回代码时就会产生僵死(尸)进程僵死进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码。所以,只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入Z状态 。

僵尸状态的例子

以下为一个维持30秒的僵尸状态例子:

 #include <stdio.h>
 #include <stdlib.h>
 #include<sys/types.h>
 #include<unistd.h>                                                                     
 int main()
  {
  pid_t id = fork();
  if(id < 0){
  perror("fork");
  return 1;
  }
  else if(id > 0){ //parent
  printf("parent[%d] is sleeping...\n", getpid());
  sleep(30);
  }else{
  printf("child[%d] is begin Z...\n", getpid());
  sleep(5);
  exit(EXIT_SUCCESS);
  }
  return 0;
  }


孤儿进程

       父进程如果提前退出,那么子进程后退出,进入Z之后,那该如何处理呢?

       父进程先退出,子进程就称之为“孤儿进程”。

       孤儿进程被1号init进程领养,当然要有init进程回收喽 。

       以下为一个例子:

  #include <stdio.h>
  #include <stdlib.h>
  #include <unistd.h>
  #include <stdlib.h>
  #include <sys/types.h>
  int main()
  {
  pid_t id = fork();
  if(id < 0){
  perror("fork");
  return 1;
  }
  else if(id > 0){ //parent
  printf("i am parent[%d]\n", getpid());
  sleep(3);                                                                              
  exit(2);
  }else{
  printf("i am child[%d] \n", getpid());
  sleep(10);
  }
  return 0;
  }


                  感谢你耐心的看到这里ღ( ´・ᴗ・` )比心,如有哪里有错误请踢一脚作者o(╥﹏╥)o!

相关文章
|
存储 Linux API
【Linux进程概念】—— 操作系统中的“生命体”,计算机里的“多线程”
在计算机系统的底层架构中,操作系统肩负着资源管理与任务调度的重任。当我们启动各类应用程序时,其背后复杂的运作机制便悄然展开。程序,作为静态的指令集合,如何在系统中实现动态执行?本文带你一探究竟!
【Linux进程概念】—— 操作系统中的“生命体”,计算机里的“多线程”
|
算法 Linux 调度
深入理解Linux操作系统的进程管理
本文旨在探讨Linux操作系统中的进程管理机制,包括进程的创建、执行、调度和终止等环节。通过对Linux内核中相关模块的分析,揭示其高效的进程管理策略,为开发者提供优化程序性能和资源利用率的参考。
442 32
|
11月前
|
并行计算 Linux
Linux内核中的线程和进程实现详解
了解进程和线程如何工作,可以帮助我们更好地编写程序,充分利用多核CPU,实现并行计算,提高系统的响应速度和计算效能。记住,适当平衡进程和线程的使用,既要拥有独立空间的'兄弟',也需要在'家庭'中分享和并行的成员。对于这个世界,现在,你应该有一个全新的认识。
372 67
|
10月前
|
Web App开发 Linux 程序员
获取和理解Linux进程以及其PID的基础知识。
总的来说,理解Linux进程及其PID需要我们明白,进程就如同汽车,负责执行任务,而PID则是独特的车牌号,为我们提供了管理的便利。知道这个,我们就可以更好地理解和操作Linux系统,甚至通过对进程的有效管理,让系统运行得更加顺畅。
280 16
|
10月前
|
Unix Linux
对于Linux的进程概念以及进程状态的理解和解析
现在,我们已经了解了Linux进程的基础知识和进程状态的理解了。这就像我们理解了城市中行人的行走和行为模式!希望这个形象的例子能帮助我们更好地理解这个重要的概念,并在实际应用中发挥作用。
201 20
|
9月前
|
监控 Shell Linux
Linux进程控制(详细讲解)
进程等待是系统通过调用特定的接口(如waitwaitpid)来实现的。来进行对子进程状态检测与回收的功能。
211 0
|
9月前
|
存储 负载均衡 算法
Linux2.6内核进程调度队列
本篇文章是Linux进程系列中的最后一篇文章,本来是想放在上一篇文章的结尾的,但是想了想还是单独写一篇文章吧,虽然说这部分内容是比较难的,所有一般来说是简单的提及带过的,但是为了让大家对进程有更深的理解与认识,还是看了一些别人的文章,然后学习了学习,然后对此做了总结,尽可能详细的介绍明白。最后推荐一篇文章Linux的进程优先级 NI 和 PR - 简书。
285 0
|
9月前
|
存储 Linux Shell
Linux进程概念-详细版(二)
在Linux进程概念-详细版(一)中我们解释了什么是进程,以及进程的各种状态,已经对进程有了一定的认识,那么这篇文章将会继续补全上篇文章剩余没有说到的,进程优先级,环境变量,程序地址空间,进程地址空间,以及调度队列。
167 0
|
9月前
|
Linux 调度 C语言
Linux进程概念-详细版(一)
子进程与父进程代码共享,其子进程直接用父进程的代码,其自己本身无代码,所以子进程无法改动代码,平时所说的修改是修改的数据。为什么要创建子进程:为了让其父子进程执行不同的代码块。子进程的数据相对于父进程是会进行写时拷贝(COW)。
228 0
|
存储 网络协议 Linux
【Linux】进程IO|系统调用|open|write|文件描述符fd|封装|理解一切皆文件
本文详细介绍了Linux中的进程IO与系统调用,包括 `open`、`write`、`read`和 `close`函数及其用法,解释了文件描述符(fd)的概念,并深入探讨了Linux中的“一切皆文件”思想。这种设计极大地简化了系统编程,使得处理不同类型的IO设备变得更加一致和简单。通过本文的学习,您应该能够更好地理解和应用Linux中的进程IO操作,提高系统编程的效率和能力。
559 34