首页 联络聊天正文

有两个这样的进程:僵尸进程&孤儿进程,蓝瘦香菇

访客 联络聊天 2020-07-29 15:32:40 11 0 进程香菇僵尸
标示 描述 UID 用户ID PID 进程ID PPID 父进程ID C 进程占cpu百分比 STIME 进程启动的时间 TTY 终端机位置 TIME 实际使用cpu的时间 CMD 命令以及参数

我们现在知道了每个参数的含义,既然讲到进程嘛,首先,进程ID是唯一的并且是非负数的,但是进程ID是可以复用的,毕竟进程也会终止。


可以看到没有进程PID是0的,这是为什么呢? 黑人问号脸?


0一般来说是系统进程,属于内核的一部分,不执行任何磁盘上的程序。


fork

一个进程可以通过调用fork函数创建新的进程,被创建出来的这个进程就叫子进程。


这里需要注意一下,fork函数的返回值父子进程区别。


  • 子进程 : 返回值是0,返回0的理由是子进程的父进程是可以唯一确定的,通过getppid方法可以获取到父进程id。
  • 父进程 : 返回的是新创建的子进程的id,因为父进程可以有多个子进程,也没有这样的函数可以获取该线程的子线程的所有id。

下边的话我们来验证一下上说的这一段话。准备好脚本。


#include <sys/types.h>#include <unistd.h>#include <stdio.h>int main(int argc, char const *argv[]){ pid_t p1 = fork(); printf("%dn",p1); if(p1 > 0) { printf("父进程 pid = %d, p1 = %dn", getpid(), p1); } else { printf("子进程 pid = %d , ppid = %d, p1 = %dn", getpid(), getppid(), p1); } return 0;}复制代码

运行看结果:


[root@iz2ze76ybn73dvwmdij06zz ~]# ./fork210213父进程 pid = 10212, p1 = 102130子进程 pid = 10213 , ppid = 10212, p1 = 0复制代码

通过上面的小例子我们可以看到父进程的返回值是子进程的ID,子进程的返回是0。


孤儿进程

孤儿我们都懂就是。。。



是的,没错孤儿进程也是这样的,就是没有父进程的进程。当然创建的时候肯定是要先创建父进程了,当父进程退出时,它的子进程们(一个或者多个)就成了孤儿进程了。


接下来在继续做一个小测试,让父进程现退出。准备好脚本。


[root@iz2ze76ybn73dvwmdij06zz ~]# cat guer.c#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <errno.h>int main(){ pid_t pid = fork(); if (pid < 0) { perror("fork error;"); exit(1); } else if (pid == 0) { sleep(5); printf ("子进程 : [ pid] = %d , 父进程 [ppid] = %dn",getpid(),getppid()); exit(0); } else if (pid > 0) { printf("我是父线程,我先退出一步~n"); exit(0); } return 0;}复制代码

执行并看结果:



到这里估计很多童鞋估计已经看懂了,父进程退出后,子进程被一个进程ID为1的进程领养的。还挺好这个结果,至少还是有人管的,被暖到了~ 进程id为1的进程是init进程,每当有孤儿进程出现时,init进程就会收养它并成为它的父进程 ,来照顾它以孤儿进程以后的生活。


危害

因为孤儿进程会被init进程接管,所以孤儿进程是没有危害的。


僵尸进程

和孤儿进程相反的是,这次是子进程先退出,而父进程又没有去处理回收释放子进程的资源,这个时候子进程就成了僵尸进程。


先准备好代码:


[root@iz2ze76ybn73dvwmdij06zz ~]# cat zombie.c #include <stdio.h> #include <unistd.h> #include <errno.h> #include <stdlib.h> int main() { pid_t pid; pid = fork(); if (pid < 0) { perror("fork error:"); exit(1); } else if (pid == 0) { printf("我是子进程,我要先退出一步了.n"); printf("子进程 id : %dn" ,getpid()); exit(0); } else { printf("我是父进程,我先睡2秒n"); printf("父进程 id : %dn" ,getpid()); sleep(2); while(2); //来个死循环,不退出的那种 } return 0; }复制代码

运行看下结果:



再来开一个终端看下进程结果:



大家可以看到,子进程并没有完全退出,释放资源,而是变成了僵尸进程。


危害

资源上是占用不了什么资源。但是通常系统的进程数量都是有限制的,如果有大量的僵尸进程占用进程号,导致新的进程无法创建,这个危害类似于占个坑,不办事,别人也办不了事。


处理1.干掉父进程

干掉父进程后,让剩下的子进程成为孤儿进程,成为孤儿进程后就和我们上面说的一样了,由init进程来领养这些进程,并且来处理这些进程的资源释放等工作。


2.父进程调用wait或waitpid

等函数等待子进程结束,这会导致父进程挂起。 执行wait()或 waitpid()系统调用,则子进程在终止后会立即把它在进程表中的数据返回给父进程,此时系统会立即删除该进入点。在这种情形下就不会产生defunct进程。


3.fork两次

第一次 fork : 父进程fork一个子进程


第二次 fork : 子进程fork一个孙进程后退出


那么孙进程被init接管,当孙进程结束后,init会回收。


但子进程的回收还要自己做。


4.signal函数

父进程来处理:用signal函数为SIGCHLD安装handler,在子进程结束后,父进程会收到该信号,可以在handler中调用wait回收。


内核来处理: 如果父进程不关心子进程什么时候结束,可以通过以下两个函数通知内核自己不感兴趣子进程的结束,此时,子进程结束后,内核会回收并不再给你父进程发信号。


  • signal(SIGCLD, SIG_IGN)
  • signal(SIGCHLD, SIG_IGN)
总结

本来以为简单的一个问题,没想到这个篇幅其实也不算短,所以感觉程序员真的不能说一个什么知识点就简单,很容易理解啊,一旦你想要深入也是需要一定的时间花费和精力的~


版权声明

旭日软件园-提供免费小软件下载,电脑教程和QQ表情包下载为主要宗旨.同时有网站运营,
编程教程,网页特效,手机教程,游戏攻略和IT资讯等内容,打造常用软件下载、内容丰富的站长学习!

本文链接:http://www.webmaster5u.com/jtdh/457.html

评论