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!

相关文章
|
27天前
|
运维 关系型数据库 MySQL
掌握taskset:优化你的Linux进程,提升系统性能
在多核处理器成为现代计算标准的今天,运维人员和性能调优人员面临着如何有效利用这些处理能力的挑战。优化进程运行的位置不仅可以提高性能,还能更好地管理和分配系统资源。 其中,taskset命令是一个强大的工具,它允许管理员将进程绑定到特定的CPU核心,减少上下文切换的开销,从而提升整体效率。
掌握taskset:优化你的Linux进程,提升系统性能
|
22天前
|
弹性计算 Linux 区块链
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
30 4
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
|
4天前
|
Linux 调度
Linux源码阅读笔记05-进程优先级与调度策略-实战分析
Linux源码阅读笔记05-进程优先级与调度策略-实战分析
|
23天前
|
缓存 监控 Linux
入职必会-开发环境搭建40-Linux常用操作-Linux进程管理
进程是正在执行的程序或命令。每个进程独立的,都有需要占用一定的系统资源。Linux系统中启动进程有两种方式:1.Linux操作系统启动的时自动启动的进程。2.用户在终端输入命令启动的进程。
入职必会-开发环境搭建40-Linux常用操作-Linux进程管理
|
4天前
|
Linux API C语言
Linux源码阅读笔记02-进程原理及系统调用
Linux源码阅读笔记02-进程原理及系统调用
|
7天前
|
Linux Shell 调度
【在Linux世界中追寻伟大的One Piece】Linux进程概念
【在Linux世界中追寻伟大的One Piece】Linux进程概念
15 1
|
5天前
|
Linux
Linux 查找进程所在目录
Linux 查找进程所在目录
15 0
|
7天前
|
缓存 Linux Shell
【在Linux世界中追寻伟大的One Piece】Linux进程控制
【在Linux世界中追寻伟大的One Piece】Linux进程控制
13 0
|
1月前
|
Linux
Linux —— 进程间通信
Linux —— 进程间通信
28 1
|
15天前
|
监控 Linux Shell
探索Linux操作系统下的进程管理
【8月更文挑战第4天】本文深入探讨了在Linux操作系统下进行进程管理的方法与技巧,通过实例分析展示了如何利用系统命令和脚本来监控、控制进程。文中不仅介绍了基础的进程查看、启动、终止操作,还详细解释了如何通过信号机制处理进程间的通信,以及如何编写自动化脚本以优化日常管理任务。文章旨在为系统管理员和开发人员提供实用的进程管理知识,帮助他们更高效地维护Linux系统。