僵尸进程:子进程退出后,父进程还没有回收子进程的资源,那么这个子进程就处于僵尸状态。
Q1:“资源”是些什么?
Q2:父进程如何回收子进程的资源?

内核为每个终止子进程保存了一定量的信息,所以当终止进程的父进程调用wait或waitpid时,可以得到这些信息。
这些信息至少包括进程ID,该进程的终止状态,以及该进程使用的CPU时间总量.
内核可以释放终止进程所使用的所有存储区,关闭其所有打开的文件.

如果编写一个长期运行的程序,他调用fork产生了很多子进程,那么除非父进程等待来取得子进程的终止状态,否则这些子进程终止后就会变成僵尸进程。

避免僵尸进程的方法
方法1:调用两次fork可以避免僵尸进程的产生。

 #include <stdio.h>
#include <stdlib.h> int main(void)
{
pid_t pid; if ((pid = fork()) < )
{
printf("fork error\n");
exit(-);
}
else if (==pid) /*first child*/
{
printf("1first child pid=%d\n", getpid());
if ((pid = fork())<)
{
printf("fork error\n");
exit(-);
}
else if (pid > ) /*parent from second fork == first child*/
{
printf("2first child pid=%d, first child exit\n", getpid());
exit();//first child exit
} printf("second child pid=%d\n", getpid());
/*I am the second child, my parent become init as soon as my real parent calls exit() in the statement above
* Here's where we'd continue executing, knowing that when we're done, init will reap out status*/
sleep();
printf("second child, parent pid = %d, second child exit\n", getppid());
exit();
} printf("pararent pid=%d\n", getpid());
if (waitpid(pid, NULL, ) != pid) /*wait for first child*/
{
printf("waitpid error\n");
exit(-);
}
printf("parent exit"); /*I am the parent(the original process); I continue executing, knowing that I'm not the parent of the second child*/ exit();
}

方法2:当SIGCHLD的处理方式是系统默认时,父进程调用了wait()以避免僵尸进程的产生,此方法中,父进程阻塞。

 #include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <errno.h>
#include <signal.h> void print_exit(int status)
{
if (WIFEXITED(status))
printf("normal termination, exit status = %d\n", WEXITSTATUS(status));
else if (WIFSIGNALED(status))
printf("abnormal termination, signal number = %d%s\n", WTERMSIG(status),
#ifdef WCOREDUMP
WCOREDUMP(status) ? ("core file generated") : (""));
#else
"");
#endif
else if (WIFSTOPPED(status))
printf("child stopped, signal number=%d\n", WSTOPSIG(status));
} void sig_child(int signo)
{
int status;
int ret;
ret = wait(&status);
printf("pid:%d, res:%d, status=%d, %s\n", getpid(), ret, status, strerror(errno));
print_exit(status);
} void sig_usr(int signo)
{
if (signo == SIGUSR1)
printf("received SIGUSR1\n");
else if (signo == SIGUSR2)
printf("received SIGUSR2\n");
else
printf("received signal %d\n", signo);
} int main(int argc, char** argv)
{
pid_t pid;
int status;
int ret; if ((pid=fork()) < )
{
printf("fork error\n");
return -;
}
else if (pid == )
{
printf("child exit\n");
return ;
}
else
{
//printf("parent sleep(100)\n");
//sleep(100);
ret = wait(&status);
print_exit(status);
printf("parent exit\n");
} exit();
}

方法3:当SIGCHLD的处理方式是捕获时,在其信号处理程序中调用wait()函数以避免僵尸进程的产生,此方法中,父进程不阻塞。

 #include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <errno.h>
#include <signal.h> void print_exit(int status)
{
if (WIFEXITED(status))
printf("normal termination, exit status = %d\n", WEXITSTATUS(status));
else if (WIFSIGNALED(status))
printf("abnormal termination, signal number = %d%s\n", WTERMSIG(status),
#ifdef WCOREDUMP
WCOREDUMP(status) ? ("core file generated") : (""));
#else
"");
#endif
else if (WIFSTOPPED(status))
printf("child stopped, signal number=%d\n", WSTOPSIG(status));
} void sig_child(int signo)
{
int status;
int ret;
ret = wait(&status);
printf("pid:%d, res:%d, status=%d, %s\n", getpid(), ret, status, strerror(errno));
print_exit(status);
} void sig_usr(int signo)
{
if (signo == SIGUSR1)
printf("received SIGUSR1\n");
else if (signo == SIGUSR2)
printf("received SIGUSR2\n");
else
printf("received signal %d\n", signo);
} int main(int argc, char** argv)
{
pid_t pid;
struct sigaction act, oact;
int status;
int ret; act.sa_handler = sig_child;
sigemptyset(&act.sa_mask);
//act.sa_flags = 0|SA_NOCLDWAIT;
sigaction(SIGCHLD, &act, &oact); if ((pid=fork()) < )
{
printf("fork error\n");
return -;
}
else if (pid == )
{
printf("child exit\n");
return ;
}
else
{
printf("parent sleep(100)\n");
sleep();
printf("parent exit\n");
} exit();
}

从打印中可以看出,信号处理程序由父进程调用
方法4:设置SIGCHLD为SA_NOCLDWAIT,当子进程终止时,不创建僵尸进程。父进程中不需调用wait。

 #include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <errno.h>
#include <signal.h> void print_exit(int status)
{
if (WIFEXITED(status))
printf("normal termination, exit status = %d\n", WEXITSTATUS(status));
else if (WIFSIGNALED(status))
printf("abnormal termination, signal number = %d%s\n", WTERMSIG(status),
#ifdef WCOREDUMP
WCOREDUMP(status) ? ("core file generated") : (""));
#else
"");
#endif
else if (WIFSTOPPED(status))
printf("child stopped, signal number=%d\n", WSTOPSIG(status));
} void sig_usr(int signo)
{
if (signo == SIGUSR1)
printf("received SIGUSR1\n");
else if (signo == SIGUSR2)
printf("received SIGUSR2\n");
else
printf("received signal %d\n", signo);
} int main(int argc, char** argv)
{
pid_t pid;
struct sigaction act, oact;
int status;
int ret; act.sa_handler = sig_usr;
sigemptyset(&act.sa_mask);
act.sa_flags = |SA_NOCLDWAIT;
sigaction(SIGCHLD, &act, &oact); if ((pid=fork()) < )
{
printf("fork error\n");
return -;
}
else if (pid == )
{
printf("child exit\n");
return ;
}
else
{
printf("parent sleep(100)\n");
sleep();
//ret = wait(&status);
//print_exit(status);
printf("parent exit\n");
} exit();
}

zombie process的更多相关文章

  1. linux zombie process相关学习

    1. zombie process是什么? zombie process是那些在系统中已经死掉的process, 通过ps -A | grep defunct可以查看系统中有多少zombie proc ...

  2. 僵尸进程(zombie process)

    僵尸进程(zombie process) http://blog.csdn.net/crfoxzl/article/details/2124718 杀死Linux中的defunct进程(僵尸进程)的方 ...

  3. linux 杀掉僵尸进程 (zombie process, defunct)

    本文说明为什么会出现僵尸进程 (zombie process, defunct),以及如何杀掉僵尸进程 1. 为什么有僵尸进程 僵尸进程出现在父进程没有回收子进程的 PCB 的时候,这个时候子进程已经 ...

  4. 僵尸进程(zombie process)

    首先了解一下linux中进程的5大状态: R Running or runnable (on run queue)S Interruptible sleep (waiting for an event ...

  5. 避免产生僵尸进程的N种方法(zombie process)

    http://blog.csdn.net/duyiwuer2009/article/details/7964795 认识僵尸进程 1.如果父进程先退出 子进程自动被 init 进程收养,不会产生僵尸进 ...

  6. Linux Process VS Thread VS LWP

    Process program program==code+data; 一个进程可以对应多个程序,一个程序也可以变成多个进程.程序可以作为一种软件资源长期保存,以文件的形式存放在硬盘 process: ...

  7. Linux进程状态 ( Linux Process State Codes)

    进程状态代码及说明: STATE代码 说明 D 不可中断的睡眠. 通常是处于I/O之中. R 运行中/可运行. 正处于运行队列中. S 可中断的睡眠. 等待某事件发生. T 已停止. 可能是因为she ...

  8. Linux编程学习笔记 -- Process

    进程是一个程序的运行.   在一个程序中执行另一个执程序的方法有两种: 1)system 在shell中执行程序 2)fork + exec 复制一个进程,在进程中用新的程序替换原有的程序   for ...

  9. process thread Fiber(linux)

    http://blog.chinaunix.net/uid-21084809-id-2215376.html Processes, kernel threads, user threads, and ...

随机推荐

  1. 【BZOJ3167/4824】[Heoi2013]Sao/[Cqoi2017]老C的键盘

    [BZOJ3167][Heoi2013]Sao Description WelcometoSAO(StrangeandAbnormalOnline).这是一个VRMMORPG,含有n个关卡.但是,挑战 ...

  2. [Atcoder Grand Contest 001] Tutorial

    Link: AGC001 传送门 A: …… #include <bits/stdc++.h> using namespace std; ; ]; int main() { scanf(& ...

  3. [BZOJ 1926] 粟粟的书架

    BZOJ 传送门 Luogu 传送门 BZOJ的sillyB评测机各种无故CE,只好去Luogu上A了o(╯□╰)o Solution: 从数据范围可以发现,这其实是2道题: (1)一个$R*C$的矩 ...

  4. JQuery获取第几个元素和判断元素在第几个

    HTML代码: <ul> <li>jQuery判断当前元素是第几个元素示例</li> <li>jQuery获取第N个元素示例</li> &l ...

  5. JavaScript对JSON数据进行排序

    var ajson= { "result":[ { "cid":1, "name":"aaa", "price ...

  6. CSS3:绘制图形

    CSS画图形,基本上所有的实现都是对边框的角度的调整及组合. 以下不包含兼容浏览器的前缀,请使用时在border-radius前加-moz-.-webkit- .... 1.正常得不得了的矩形 .sq ...

  7. Jquery获取对象的几种方式介绍

    参考: 1.http://blog.csdn.net/zengyonglan/article/details/53995295 2.http://api.jquery.com/category/sel ...

  8. flask-assets使用介绍

    作用:对css.js静态文件进行打包,打包成一个文件,然后去除文件里的换行.空行等进行压缩: 而且 Flask-Assets 还会使用特定的 HTTP Response Header, 让浏览器缓存这 ...

  9. Java练习:tips.Print

    在学习Java时和<编程导论(Java)>中,大量使用了重载的System.out.println()等类似的输出语句.特别是书籍中,一行语句中包括System.out.println会显 ...

  10. sql where 1=1和 0=1 的作用(多条件查询错误的问题)

    where 1=1; 这个条件始终为True,在不定数量查询条件情况下.1=1能够非常方便的规范语句. 一.不用where  1=1  在多条件查询中的困扰 举个样例,假设您做查询页面,而且.可查询的 ...