博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
僵尸进程示例分析------顺便说说linux中的wait和waitpid
阅读量:4142 次
发布时间:2019-05-25

本文共 3653 字,大约阅读时间需要 12 分钟。

        在之前的博文中, 我们说过孤儿进程, 在unix/linux中, 如果子进程活着, 而父进程死亡, 那么子进程就是孤儿进程, 很形象吧。 

 

        今天我们说说僵尸进程, 在unix/linux中, 如果父进程还活着, 但子进程死了, 那么unix/linux不会轻易地让子进程消息得一干二净, 而是会让子进程变成僵尸进程, 目的是为了保存一些子进程的信息, 便于让父进程知道。 否则, 子进程干干净净彻彻底底地不留痕迹地死去, 父进程会伤心的。

        僵尸进程的存在, 是为了遗留信息和线索, 但会占据系统资源, 所以应该由父进程来收尸, 获取僵尸中的信息, 知道子进程是怎么死去的, 说不定会找公安机关去报案呢。

 

        我么来看看程序:

 

#include 
#include
#include
#include
int main(){ pid_t pid; pid = fork(); if (pid < 0) { printf("fork error\n"); return 1; } if (pid == 0) // 子进程 { printf("this is child process\n"); return 0; } // 父进程继续 printf("this is father process\n"); sleep(3); // 让子进程先退出 system("ps -o pid,ppid,state,tty,command"); getchar(); return 0;}

       看看结果:

 

 

xxxxxx:~> ./a.out this is child processthis is father process  PID  PPID S TT       COMMAND17330 17328 S pts/0    -bash19219 17330 S pts/0    ./a.out19220 19219 Z pts/0    [a.out] 
19221 19219 R pts/0 ps -o pid,ppid,state,tty,command

        看到那个Z(zombie)没? 这就是僵尸进程。 此时, 父进程依然活着。  如果此时杀死父进程, 那么已经成为僵尸进程的子进程会变成“僵尸孤儿进程”, 会被pid为1的init进程进程领养, 而init进程比较特殊, 它会对自己的子僵尸进程进行自动收尸, 应用程序不用管。

 

       那么, 应用程序该如何对自己的子僵尸进程进行收尸呢? 其实很简单, wait和waitpid就是用来替僵尸进程收尸的。

       既然wait和waitpid都是用来收尸的, 那么他们有什么区别呢? 这样的问题, 网上到处都是介绍, 我就不再啰嗦了。 我只想说, waitpid是更高级版的wait, 功能更全量, 更强大, 所以, 与waitpid比起来, wait是个鸡肋。 在fork模型的多进程服务器中, 为了处理僵尸进程, waitpid能做到wait所做不到的事情, 看Stevens网络编程就知道这点。

       所以, 我们直接说waitpid,  看看代码:

 

#include 
#include
#include
#include
#include
#include
void sig_child(int signo){ pid_t pid; int stat; // 循环收尸(非阻塞) while ((pid = waitpid(-1, &stat, WNOHANG)) > 0) { printf("kill zombie child %u \n", pid); }}int main(){ pid_t pid; signal(SIGCHLD, sig_child); pid = fork(); if (pid < 0) { printf("fork error:"); return 1; } if (pid == 0) { printf("this is child process, pid is %u\n",getpid()); return 0; } printf("this is father process\n"); sleep(3); system("ps -o pid,ppid,state,tty,command"); getchar(); return 0;}

       结果:

 

 

xxxxxx:~> ./a.out this is child process, pid is 20571kill zombie child 20571 this is father process  PID  PPID S TT       COMMAND17330 17328 S pts/0    -bash20570 17330 S pts/0    ./a.out20572 20570 R pts/0    ps -o pid,ppid,state,tty,command

       可见, 僵尸的子进程被彻底清除, 没有Z了。

 

       说到这里, 大家应该想到, 回收僵尸进程, 除了用wait和waitpid之外, 直接杀死其父进程不就可以吗? 是的。 杀死父进程后, 僵尸的子进程被init进程领养, 进而在死时被init自动收尸。 所以, 我们自然可以想到如下模型: 

       爷爷进程----父亲进程----孙子进程。 杀死父进程, 让爷爷进程来收尸, 然后孤单的孙子进程自动由init进程领养(继父), 不需要年迈的爷爷进程过问了。

       所以, 两次fork搞起:

 

#include 
#include
#include
#include
#include
#include
int main(){ // 爷爷进程 pid_t pid; pid = fork(); if (pid < 0) { printf("fork error 1\n"); return 1; } if (pid == 0) // 父亲进程 { printf("father process, pid:%u, ppid:%u\n", getpid(), getppid()); pid = fork(); if (pid < 0) { printf("fork error 2\n"); return 1; } if (pid > 0) // 还是父亲进程 { printf("father process over\n"); return 0; // 父亲进程退出, 变成僵尸进程, 让爷爷进程来收尸 } // 孙子进程, 被init进程领养 printf("grandson process, pid: %u, ppid:%u\n",getpid(), getppid()); getchar(); return 0; } // 爷爷进程对父亲进程进程收尸 if (waitpid(pid, NULL, 0) != pid) { printf("waitepid error\n"); return 1; } printf("grandpa process over\n"); return 0;}

       结果:

 

 

xxxxxx:~> ./a.out father process, pid:22851, ppid:22850grandson process, pid: 22852, ppid:22851father process overgrandpa process overxxxxxx:~>

       再看进程:

 

 

xxxxxx:~> ps -ef | grep a.out 1000     22852     1  0 02:19 pts/0    00:00:00 ./a.out1000     22865 17665  0 02:19 pts/1    00:00:00 grep a.out

       可以看到, 爷爷进程和父亲进程都over了(也不会存在僵尸了), 而孙子进程还活得好好的, 被进程号为1的init进程所领养。 此后, 如果孙子进程挂了, init进程会自动来收尸的。

 

       先说这么多。

 

 

转载地址:http://mnwti.baihongyu.com/

你可能感兴趣的文章
【JavaScript 教程】浏览器—History 对象
查看>>
这才是学习Vite2的正确姿势!
查看>>
7 个适用于所有前端开发人员的很棒API,你需要了解一下
查看>>
25个构建Web项目的HTML建议,你需要了解一下!
查看>>
【web素材】02-10款大气的购物商城网站模板
查看>>
6种方式实现JavaScript数组扁平化(flat)方法的总结
查看>>
49个在工作中常用且容易遗忘的CSS样式清单整理
查看>>
20种在学习编程的同时也可以在线赚钱的方法
查看>>
隐藏搜索框:CSS 动画正反向序列
查看>>
127个超级实用的JavaScript 代码片段,你千万要收藏好(上)
查看>>
【视频教程】Javascript ES6 教程27—ES6 构建一个Promise
查看>>
【5分钟代码练习】01—导航栏鼠标悬停效果的实现
查看>>
127个超级实用的JavaScript 代码片段,你千万要收藏好(中)
查看>>
127个超级实用的JavaScript 代码片段,你千万要收藏好(下)
查看>>
【web素材】03-24款后台管理系统网站模板
查看>>
Flex 布局教程:语法篇
查看>>
年薪50万+的90后程序员都经历了什么?
查看>>
2019年哪些外快收入可达到2万以上?
查看>>
【JavaScript 教程】标准库—Date 对象
查看>>
前阿里手淘前端负责人@winter:前端人如何保持竞争力?
查看>>