免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2487 | 回复: 0
打印 上一主题 下一主题

僵尸进程 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-09-27 16:13 |只看该作者 |倒序浏览
很老的话题了,最近用到了,所以记下来。

所谓僵尸进程,即Zombie进程。当一个进程已经结束,但是系统没有把它的进程的数据结构完全释放,此时用ps 察看它的状态是defunt。 僵尸进程占据进程表的空间,而且不能被kill掉因为它已经死了,所以在开发多进程尤其是守护进程时注意要避免产生僵尸进程。

僵尸进程的产生原因是什么呢?
当UNIX系统中1个进程结束,init即1号进程会检查该进程有没有子进程,如果有,init就会接管这些子进程,把这些子进程的ppid改成1。
同时init会用信号SIGCHLD通知该进程的父进程。如果父进程用wait()或者waitpid()来获取子进程的状态的话,那么进程的相关状态数据返给父进程之后,该进程自身将被销毁。
那么考虑一种情况,如果父进程没有使用wait或waitpid呢? 此时因为子进程的状态数据没有被取走,所以该子进程即变成了僵尸进程。

解决方法通常有3种
1)2次fork
父进程
    pid_t pid;
    switch ( pid = fork() ) {
       case -1:           break;
       case 0:
         execl("xxx", "xxx", (char*)0,(char*)0);
         exit(-1);
       default:
         waitpid(pid, NULL, 0); //we wait to avoid zombie
         break;
子进程 xxx
    pid_t pid;
    switch ( pid = fork() ) {
       case -1:           break;
       case 0:
         /* 做子进程自己的动作 */
         sleep(1); // sleep 1 second to let the parent go firstly
         exit(-1);
       default:
         break;
     }

可以看到,子进程中又fork了一次,产生的孙进程做实际的操作,而子进程迅速结束返回,这样父进程可以快速回收。而孙进程将被init进程接管。

2)捕获SIGCHLD,然后waitpid
使用sigaction()为SIGCHLD安装一个handler,然后在handler里使用waitpid
static void sig_handler(int signo) {
  int stat;
  while(waitpid(-1,&stat,WNOHANG)>0)
  ;
  return;
}
为什么用while是因为可能有多个子进程,而多个SIGCHLD并不会排队。
不要用signal()函数来设handler,因为那不可靠。

当然如果父进程可以阻塞执行,等待子进程完成,那么不用安装信号,直接waitpid即可。通常不会这么做。

3)设置SIGCHLD的动作为 SA_NOCLDWAIT
使用sigaction()对SIGCHLD的flag设置 SA_NOCLDWAIT,通知系统不产生僵尸。
该方法没有试过。

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/17004/showart_1227357.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP