Linux下具体的进程状态详细解析!!!

Linux的进程状态

概述

在linux下具体的进程状态如图所示有以下几种,进程的状态用state整形表示(state是什么)

此处使用了位掩码(bitmask)的技术,这里每一个状态的值都是2的幂,则可以用state的各个二进制位来表示一个当前状态,为0则不处于,为1则处于该状态

RunningState(运行状态)

什么是运行状态

int main(){
    while(1){}
    return 0;
}

在这里插入图片描述

通过运行结果可以看到,死循环执行时,myprocess程序的STAT为R+,此处的R就为运行状态(+号跳转),并且由于有时间片的限制(时间片),该程序并不会一直在CPU上跑,但是STAT一直为R+状态,则说明此处的R表示进程正在CPU上被运行或是正处于CPU的运行队列里

前台与后台进程

前台

当使用./可执行程序名字,是把当前程序放到前台运行,可以直接使用Ctrl+c来终止程序,并且在进程状态后会有一个+号表示是前台进程,上图所示,myprocess为R+,即处于前台Running(运行)状态

在这里插入图片描述

当输入命令时bash没有反应,因为前台正在被myprocess进程占据

后台

使用./程序名 &则把当前程序运行到后台上,此时bash依然占据前台,则输入的命令是有效的

在这里插入图片描述

在这里插入图片描述

当前的myprocess处于R状态没有+号,表明+号被用来区分前后台,有+号前台,无+号后台

在后台运行的程序不能够使用Ctrl+c来杀掉进程,需要使用kill -9 pid

SleepingState(睡眠状态)

什么是睡眠状态

S也被称为可中断睡眠\浅度睡眠(interruptible sleep)
此状态表示正在等待软硬件资源的就绪,下面以键盘输入为例

int main(){
    int a;
    scanf("%d",&a);
    printf("%d\n",a);
    return 0;
}

在这里插入图片描述

此时myprocess运行到scanf正在等待键盘输入资源,STAT为S+,由于正在等待资源的就绪此时进程在键盘的等待队列中,则S为操作系统维度下的堵塞状态的一种(堵塞状态)

该状态可使用Ctrl+C来进行中断

在这里插入图片描述

sleep和printf状态分析

int main(){
    while(1){
        sleep(1);
    }
    return 0;
}

在这里插入图片描述

此时myprocess的状态变为了S,并非是R运行状态,因为此处的sleep(把进程从CPU上调度到sleep设置的等待队列)睡眠1秒而在CPU上运行的while判断速度执行的非常快,所以睡眠的时间占百分之95甚至更多,所以当查看进程状态时,很大概率都为S

#include<unistd.h>
int main(){
    while(1){
        printf("I am a process!pid: %d",getpid());
    }
    return 0;
}

在这里插入图片描述

printf也需要等待显式器打印完成,同样需要在显式器的等待队列中等待资源的就绪,而CPU的速度远远快于显式器的打印速度,所以大多数时候都保持为S睡眠状态,这里也检测到了R状态,只不过此状态占比非常小

disk sleep(磁盘休眠)

什么是磁盘休眠

disk sleep也被称为不可中断睡眠

当内存资源严重不足时(通过swap分区唤入唤出等等的操作都用了),操作系统为了维持正常的运行,则会杀掉一部分能够杀掉的进程(OOM Killer),而有些进程正在执行非常重要的与磁盘I/O操作(例如向磁盘写入用户的重要数据),正在等待硬件资源就绪,如果被杀掉可能导致一系列非常严重的问题,从而为了使当前正在等待资源就绪的进程不能被杀掉,则引入了disk_sleep状态即不可中断睡眠,处于此状态的进程不能被杀掉

此状态也是操作系统维度下的堵塞状态的一种,一样是在等待资源的就绪,但是不能被OOM Killer杀掉

OOM Killer (内存溢出杀手)

当内存压缩与回收和swap机制依然无法解决内存不足的问题时,Linux内核会启动OOM Killer.这是一个内核级别的功能,用于在物理内存和swap都耗尽时,通过一定的选择判断来决定终止哪些进程以释放内存空间

stopped(暂停状态)

什么是暂停状态

在暂停状态下的进程不会使用CPU资源,该进程的执行已被暂时中断,但它仍然保留在系统的进程表中,并且在内存中保留所有的代码和数据
该状态可以防止进程的未被授权的操作,例如一些进程在某个时段不允许访问显式器来打印数据,此时不能够进入显式器的等待队列也不能够被CPU运行(显示器的资源未就绪),那么此时该进程就会被暂停

使用kill暂停/重启进程与前后台状态细节

int main(){
    while(1){
        printf("I am a process!pid: %d",getpid());
        sleep(1);
    }
    return 0;
} 

在这里插入图片描述

kill的19号信号为stop信号即暂停信号使进程处于暂停状态

在这里插入图片描述

进程原为S+状态即前台的睡眠状态,当被暂停后状态变为T状态即暂停状态,同时去掉了+号,即当前进程从前台转到后台,这里进程被暂停后什么都不会做,肯定需要把前台让出来此时bash进程将重新在前台执行,此时输入命令有效

在这里插入图片描述

kill -18 pid把暂停的状态重新运行起来,此时状态从T变为S,则从后台启动的进程会在后台运行,不会重新回到前台,要终止进程,只能使用kill -9 pid

trace stop(跟踪暂停)

什么是trace stop

trace stop是在使用跟踪工具对进程进行跟踪时进程所处的状态,进程会被暂停等待调试器的下一个信号来执行具体的操作,便于调试或监控

此处以gdb调试为例
在这里插入图片描述

可以看到,当在gdb中按r运行时,myprocess进程才被执行, 状态为t状态,因为此时正在被gbd追踪调试

总结暂停状态

stopped暂停等待硬件资源条件的就绪或者软件资源(例如启动信号)的就绪,而trace stop也同样是暂停等待软件资源的就绪(下一步的调试信号),则两种暂停状态也都可以归类到操作系统维度下的堵塞状态

zombie(僵尸状态)

什么是僵尸状态

当一个进程死亡时,它的代码和数据会被直接释放,但是它的task_struct(PCB)并不会立即被释放,因为一个进程执行完所有的任务(代码)后,系统需要知道进程是否是正常死亡退出的,还是在执行过程中出现错误而导致异常退出,就需要让上层从子进程的PCB中拿到死亡(退出)信息,从而判断子进程代码完成的结果数据

如果父进程一直都不去进行读取子进程退出信息(结果数据),那么处于僵尸状态的子进程会一直存在,子进程的PCB会一直占据内存空间,就会造成严重的内存泄漏!

int main(){
    pid_t id = fork();
    if(id == 0){
        exit(0);
    }                                                 
    else{
        sleep(1000);
    }
    return 0;
}

在这里插入图片描述

此时myprocess的子进程被exit退出此时处于僵尸Z状态,+号表示在前台,此处的defunct意思为失效的,不再存在的

使用wait拿取子进程的退出信息

int main(){
    pid_t id = fork();
    if(id == 0){
        exit(0);
    }
    else{
        sleep(10);
        wait(NULL);
        sleep(1000);
    }
    return 0;
}

在这里插入图片描述

使用wait使得处于Z+状态的子进程被父进程所回收,最后子进程从僵尸变为死亡

bash回收

所有bash的子进程在进入僵尸状态后都会被bash直接回收释放,即bash会自动回收,则不能直接捕捉到则没有示例

dead(死亡状态)

真正的死亡状态,进程的所有数据都被释放

孤儿进程

  • 父进程在未回收子进程的结果数据时提前退出,子进程此时的父进程还是原来的父进程吗?
  • 如果子进程处于Z状态,那么它会被回收吗,会被谁回收?
int main(){
  7   int cnt = 5;
  8   pid_t id = fork();
  9   if(id == 0){
 10     int cnt = 20;
 11     while(cnt--){
 12       printf("child process exist!\n");
 13      sleep(1);                                      
 14     }
 15     exit(0);
 16   }
 17   else{
 18    // wait(NULL);
 19     while(cnt--){
 20       printf("parent process exist!\n");
 21       sleep(1);
 22     }
 23   }
 24   printf("parent process dead\n");
 25   return 0;
 26 }

在这里插入图片描述

当父进程退出被bash回收,但子进程还在运行时,那么id为1的进程为当前子进程新的父进程

id为1的进程为init进程,所有用户空间的进程均派生自该进程

在这里插入图片描述

init进程也会自动回收僵尸状态的子进程

总结:孤儿进程为父进程提前退出的进程,此时孤儿进程的父进程变为init进程,并且处于僵尸状态会被init自动回收

  • 43
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值