zombie process
僵尸进程:子进程退出后,父进程还没有回收子进程的资源,那么这个子进程就处于僵尸状态。
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的更多相关文章
- linux zombie process相关学习
1. zombie process是什么? zombie process是那些在系统中已经死掉的process, 通过ps -A | grep defunct可以查看系统中有多少zombie proc ...
- 僵尸进程(zombie process)
僵尸进程(zombie process) http://blog.csdn.net/crfoxzl/article/details/2124718 杀死Linux中的defunct进程(僵尸进程)的方 ...
- linux 杀掉僵尸进程 (zombie process, defunct)
本文说明为什么会出现僵尸进程 (zombie process, defunct),以及如何杀掉僵尸进程 1. 为什么有僵尸进程 僵尸进程出现在父进程没有回收子进程的 PCB 的时候,这个时候子进程已经 ...
- 僵尸进程(zombie process)
首先了解一下linux中进程的5大状态: R Running or runnable (on run queue)S Interruptible sleep (waiting for an event ...
- 避免产生僵尸进程的N种方法(zombie process)
http://blog.csdn.net/duyiwuer2009/article/details/7964795 认识僵尸进程 1.如果父进程先退出 子进程自动被 init 进程收养,不会产生僵尸进 ...
- Linux Process VS Thread VS LWP
Process program program==code+data; 一个进程可以对应多个程序,一个程序也可以变成多个进程.程序可以作为一种软件资源长期保存,以文件的形式存放在硬盘 process: ...
- Linux进程状态 ( Linux Process State Codes)
进程状态代码及说明: STATE代码 说明 D 不可中断的睡眠. 通常是处于I/O之中. R 运行中/可运行. 正处于运行队列中. S 可中断的睡眠. 等待某事件发生. T 已停止. 可能是因为she ...
- Linux编程学习笔记 -- Process
进程是一个程序的运行. 在一个程序中执行另一个执程序的方法有两种: 1)system 在shell中执行程序 2)fork + exec 复制一个进程,在进程中用新的程序替换原有的程序 for ...
- process thread Fiber(linux)
http://blog.chinaunix.net/uid-21084809-id-2215376.html Processes, kernel threads, user threads, and ...
随机推荐
- CodeForces - 981E Addition on Segments
考虑每个点i在什么情况下会成为最大值. 当选的区间子集是 包含i的区间的一个子集的时候,i肯定会是最大值. 所以我们就可以用这种方法得到所有点的可能的最大值是多少... 也就是说,最后的局面可以仅由一 ...
- [BZOJ2226]LCMSum
转化一下,$\sum\limits_{i=1}^n[i,n]=n\sum\limits_{i=1}^n\dfrac i{(i,n)}$ 枚举$d=(i,n)$,上式变为$n\sum\limits_{d ...
- [xsy2369]取名字
真是道挺好的题,做一道题学了挺多东西 从操作入手比较困难,所以对硬币进行讨论 考虑一个硬币$(A,B)$,假设$A\lt B$,那么我们可以把操作分成三类 第一类$T_j\lt A$,这种操作是没用的 ...
- 【AC自动机】hdu2222 Keywords Search
AC自动机模板题,给你n个模式串和一个文本串,问你有几个模式串在文本串出现过. 注意防止重复统计 这里推荐一波郭大爷的介绍,简单易懂. http://www.bilibili.com/video/av ...
- 【最小割】【Dinic】bzoj3275 Number
每个点拆点,分别向源/汇连a[i]的边,满足条件的相互连INF的边,答案为sum-maxflow*2. 因为若有几个点不能同时被选,我们要贪心地选择其中和尽量大的部分,这可以由最小割来保证. #inc ...
- 显示字符 Exercise06_12
/** * @author 冰樱梦 * 时间:2018年下半年 * 题目:显示字符 *1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J ...
- cocos2dx 3.13 etc1 ClippingNode Bug 修正
void TrianglesCommand::useMaterial() const { if(_stencl){ /*******[solyess] etc1 mask的支持************ ...
- SQLSERVER WINDBG调试:mssqlwiki.com
https://mssqlwiki.com/2012/10/16/sql-server-exception_access_violation-and-sql-server-assertion/ SQL ...
- ztree jquery 树 控件
插件地址:http://www.ztree.me 数据:[{"id":1,"pId":-1,"name":"根目录"}, ...
- ASP.NET Core 1.0基础之诊断
来源https://docs.asp.net/en/latest/fundamentals/diagnostics.html ASP.NET Core 1.0包含了一些新的特性来辅助诊断问题.可以在S ...