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 ...
随机推荐
- iOS开发-设置在使用NavigateController时View的顶部位置
最近我在开发中遇到了一个问题,在使用NavigationController时内部的ViewController的View总是与屏幕顶部对齐,而我们有时候不需要这种效果: 在开发过程中,我们可能会 ...
- powerbuilder webbrowser 内嵌浏览器 select下拉框无法使用
Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\MA ...
- Coherence装载数据的研究 - Invocation Service
这里验证第三个方法,原理是将需要装载的数据分载在所有的存储节点上,不同的地方是利用了存储节点提供的InvocationService进行装载,而不是PreloadRequest, 原理如图 前提条件是 ...
- 深入理解JS函数作用域链与闭包问题
function fun(n,o) { console.log(o) return { fun:function(m){ return fun(m,n); } }; } ); a.fun(); a.f ...
- Java集合迭代器 Iterator分析
简介 迭代器是遍历容器的一种常用方法,它屏蔽了容器的实现细节,无需暴露数据结构内部,就可以对容器进行遍历,迭代器本身也是一种设计模式,迭代是一种特殊的遍历方式. Iterator 在java中,迭代器 ...
- Python 自用代码(某方标准类网页源代码清洗)
用于mongodb中“标准”数据的清洗,数据为网页源代码,须从中提取: 标准名称,标准外文名称,标准编号,发布单位,发布日期,状态,实施日期,开本页数,采用关系,中图分类号,中国标准分类号,国际标准分 ...
- [Flutter] Creating, Importing & Using Dynamic Widgets from Other Files in a Flutter Application
In this lesson we’ll learn how to import widgets we’ve created in other files & use them in our ...
- Eclipse重新导入Tomcat启动出错选择不了文件夹
如果你已经把tomcat配置进了Eclipse,却因为某些原因delete了服务器,再想导入同版本的服务器就有可能会报Could not publish to the server.错误,并且添加服务 ...
- node - 导包机制
在学node js的时候,经常各种导包 let http = require('http'); 然后它的运行机制: 1. 查找当前目录下面的node_modules 2. 全局查找(首先添加到path ...
- rails手脚架(scaffold)功能
scaffold是一个高速开发rails应用的代码框架.能够使用一条命令实现CRUD操作. 1: 创建一个应用 rails new scaffoldapp cd scaffoldapp rails s ...