在 Unix 进程模型中,父进程和其所产生的子进程是异步运行的,所以如果子进程在结束后,会留下一些信息需要父进程使用  wait  /  waitpid  来接收。而如果父进程太忙了,没有调用  wait  /  waitpid  的话,子进程就会变成僵尸进程

僵尸进程不可能被杀死,因为它已经死了,不存在再死一次的问题。死的对立面是活,死者已死。只有活的进程才可能被杀死。

什么是僵尸进程?

首先要明确一点,僵尸进程的含义是:子进程已经死了,但是父进程还没有wait它的一个中间状态,这个时候子进程是一个僵尸。正常情况下子死,父wait,清理掉子进程的task_struct,释放子进程的PID:

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>int main(void)
{pid_t pid,wait_pid;int status;pid = fork();if(pid == 1){perror("Cannot create new process\n");exit(1);}else if(pid == 0){printf("child process id:%ld\n",(long)getpid());pause();_exit(0);}else{#if 0printf("ppid :%d\n",getpid());while(1);#endifdo{wait_pid = waitpid(pid,&status,WUNTRACED | WCONTINUED);if(WIFEXITED(status))printf("child process is killed by signal %d\n",WIFSIGNALED(status));}while(!WIFEXITED(status) && !WIFSIGNALED(status));exit(0);}
}

执行

gcc ps_wait.c -pthread && ./a.out

执行情况如下

linux@ubuntu:~/linux$ gcc ps_wait.c -pthread && ./a.out
child process id:4578

每次执行生成的子进程会不同,这里只是举例子说明

运行,我们看到2个a.out进程

杀死子进程4578,看到父进程的打印:

之后,4578会消失,因为父进程执行到了wait,也知道了子进程是被信号2杀掉的。但是如果子进程死了,父进程不执行到wait,比如把上图中的"#if 0"改为"#if 1",杀死子进程后,子进程就会是一个僵尸:

注意,这里说的是子进程会变成一个僵尸进程

代码如下:

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>int main(void)
{pid_t pid,wait_pid;int status;pid = fork();if(pid == 1){perror("Cannot create new process\n");exit(1);}else if(pid == 0){printf("child process id:%ld\n",(long)getpid());pause();_exit(0);}else{#if 1printf("ppid :%d\n",getpid());while(1);#endifdo{wait_pid = waitpid(pid,&status,WUNTRACED | WCONTINUED);if(WIFEXITED(status))printf("child process is killed by signal %d\n",WIFSIGNALED(status));}while(!WIFEXITED(status) && !WIFSIGNALED(status));exit(0);}
}

我们重新运行,当我们用kill -2杀掉子进程4628后,我们发现4628成为一个僵尸,状态变为Z+,名字上也加了一个棺材[],成为[a.out]

Z表示的是僵尸进程,[]符号就像一口棺材一样,把这个僵尸进程给装了起来

僵尸不可能被杀死?

我们看到上面4628是个僵尸很不爽,所以我们想把它干掉,据说Linux有个信号9,神挡杀神,佛挡杀佛,我们现在来用kill -9干掉4628

从上图可以看出,我们把4628用kill -9捅了好多刀,但是最后看4628这个僵尸,还是没有消失。

因为僵尸已经是死了,它不可能再次被杀死,你给它捅一万刀,它也是个死人,不可能再次死!

僵尸不可能被杀死,因为它已经死了!

两种方法来清理僵尸进程1、只等父进程来wait清理尸体了2、这个时候我们能够把僵尸消失掉的方法,就是杀死僵尸进程的父进程4627。

一个僵尸可以被杀死的假象

下面的这个程序证明「僵尸可以被杀死」这样的假象。

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>static void *thread_fun(void *param)
{while(1);
}int main(void)
{pthread_t tid;int ret;ret = pthread_create(&tid,NULL,thread_fun,NULL);if(ret == -1){perror("cannot create new thread\n");return -1;}pthread_exit(0);return 0;
}

我们在主线程里面,pthread_create()创建线程后,pthread_exit()退出,这个时候我们会发现,在ps命令里面,a.out显示为一个僵尸进程。这个僵尸进程出现是我们在thread_fun 里面写了一个while(1)不能退出导致的。

继续,开始我们的表演,我们使用下面的命令来杀死这个僵尸进程。

kill -9 4730

我们会惊奇地发现,4730真地会从ps命令里面消失

在没有执行命令杀死 4730 之前,我们「猜测」能杀死僵尸的本质原因是,当主线程4730调用pthread_exit()退出后,主线程4730的状态确实是僵尸了,但是该进程里面的4731线程,却没有死。

我们看看proc 文件系统下面的进程状态

看看4731:

4731是活着的,证明整个进程并没有挂。所以4730的退出,只是让整个进程半死。而由于ps这些命令的误会,4730凑巧又是整个进程的PID,它显示地好像整个4370成了僵尸一样。

4731这个子进程什么时候死了呢?那么,根据POSIX标准关于信号(signal)的定义,当我们执行kill -9 4730 (4730是4730和4731的TGID,也是整个进程用户态视角的PID)的时候,是要杀死整个4730进程的,所以这个时候4731被我们杀死,整个进程就都死了,这个时候,执行到父进程的wait逻辑,导致僵尸消失。

所以,在本例中,kill -9 4730看起来是"杀死了僵尸”,实际是杀死了4730整个进程(里面的每个线程),导致整个进程死。在此之前,整个进程实际还是活的。


扫码或长按关注

回复「篮球的大肚子」进入技术群聊

Linux 僵尸进程可以被杀死吗?相关推荐

  1. JAVA项目linux僵尸进程_linux杀死僵尸进程

    ps -A -o stat,ppid,pid,cmd | grep -e '^[Zz]' | awk '{print $2}' | xargs kill -9 1.查看系统是否有僵尸进程 使用Top命 ...

  2. 转:Linux 僵尸进程详解

    Linux 僵尸进程详解 转载:http://www.51testing.com/?uid-225738-action-viewspace-itemid-206225 1.僵尸进程概念: 僵尸进程(Z ...

  3. linux defunct 进程,Linux僵尸进程(Zombie or defunct)

    僵尸进程(Zombie or defunct)关于Linux僵尸进程,一般是由于子进程结束的时候,会有一些资源没有释放掉,直到父进程结束或者由父进程去处理它才可以! www.cit.cn 僵尸进程就是 ...

  4. linux查看进程号,杀死进程

    linux查看进程号,杀死进程 文章目录 linux查看进程号,杀死进程 一.查看进程号 二.杀死进程 三.杀死用户usename下全部进程 ps -ef | grep ^usename | cut ...

  5. linux僵尸进程杀不掉,杀死僵尸进程,你需要这些神奇高效的 Linux 命令

    原标题:杀死僵尸进程,你需要这些神奇高效的 Linux 命令 Linux高手,其实都是玩儿命令行很熟练的人. 命令行的学习捷径 Linux命令有许多强大的功能:从简单的磁盘操作.文件存取,到进行复杂的 ...

  6. linux 僵尸进程 defunct

    在 Unix系统管理中,当用ps命令观察进程的执行状态时,经常看到某些进程的状态栏为defunct,这就是所谓的"僵尸"进程. "僵尸"进程是一个早已 死亡的进 ...

  7. Linux 僵尸进程

    Linux 允许进程查询内核以获得其父进程的 PID,或者其任何子进程的执行状态.例如,进程可以创建一个子进程来执行特定的任务,然后调用诸如 wait() 这样的一些库函数检查子进程是否终止.如果子进 ...

  8. 关于linux 僵尸进程

    僵尸进程是指的父进程已经退出,而该进程dead之后没有进程接受,就成为僵尸进程.(zombie)进程 怎样产生僵尸进程的: 一个进程在调用exit命令结束自己的生命的时候,其实它并没有真正的被销毁,而 ...

  9. linux僵尸进程理解,Linux僵尸进程详细解析

    在fork()/execve()过程中,假设子进程结束时父进程仍存在,而父进程fork()之前既没安装SIGCHLD信号处理函数调用waitpid()等待子进程结束,又没有显式忽略该信号,则子进程成为 ...

最新文章

  1. 长短视频之争,长视频平台和短视频源码谁主沉浮?
  2. 模拟电路推荐学习书单
  3. DataGridView 里数据的动态明细 DataGridView GridView
  4. python开发工资多少-Python开发工资多少
  5. SAP歷史更改記錄函數
  6. java 设计作业——学生类的基本练习
  7. PAT乙类1009 说反话 (20 分)
  8. (数学分析笔记)常用函数不定积分及其计算技巧
  9. 学习CGI之前,需要配置阿帕奇---windows
  10. LCA树两个节点最低公共祖先
  11. Hadoop简单介绍
  12. Cadence 17.4 等长布线
  13. 电商后台管理系统分享
  14. java运行环境(jre)_什么是JRE? Java运行时环境简介
  15. 应用程序无法启动,因为应用程序的并行配置不正确 解决方案
  16. html5手机摄像头相册批量,h5调用手机摄像头/相册(示例代码)
  17. oracle mysql 同义词,有关Oracle数据库中同义词的简单介绍
  18. 农业遥感技术科研成果汇总
  19. 2021牛年大吉,红包敬上
  20. unity2022打开项目时报Fatal error显示无权访问d3dcompiler_47.dll, 解决方法很简单-还有ucrtbase.dll问题

热门文章

  1. C#发送电子邮件 (异步) z
  2. linux文件的时间格式
  3. 使用jquery打造一个动态的预览产品颜色效果
  4. ASP.NET MVC 整合 Spring.net(1)- Controller进容器
  5. 学成在线--26.课程图片管理(图片删除)
  6. python封装继承多态_浅谈JavaScript的面向对象和它的封装、继承、多态
  7. linux 进程通信机制,linux的进程通信机制小结
  8. java虚方法和抽象方法_虚方法和抽象方法--基础回顾
  9. Git常用指令及功能总结
  10. 玩Python遇到的问题一二三及解决办法