工作中,一个模块出现了僵尸进程,大致一看应该是system调用引起的。搜了一下僵尸进程的处理。
一、僵屍進程的産生
当子进程比父进程先运行结束,而父进程没有回收子进程的时候,子进程将成为一个僵尸进程。如果父进程先退出,子进程被init接管,子进程退出后init会回收,就没事了。
二、僵屍進程的危害
僵尸进程是一个运行完毕的进程,所有资源都已经释放了,除了它的进程表项。因此,导致的影响如下:如果操作系统最多能管理1000个进程,那么僵尸进程的存在,将会使得操作系统管理正常进程减少。
三、如何避免僵屍進程的産生
1、父进程通过wait和waitpid等函数等待子进程结束,这会导致父进程挂起
2. 如果父进程很忙,那么可以用signal函数为SIGCHLD安装handler,因为子进程结束后,父进程会收到该信号,可以在handler中调用wait回收(没有试验过)
3. 如果父进程不关心子进程什么时候结束,那么可以用signal(SIGCHLD, SIG_IGN)通知内核,自己对子进程的结束不感兴趣,那么子进程结束后,内核会回收,并不再给父进程发送信号
4. 还有一些技巧,就是fork两次,父进程fork一个子进程,然后继续工作,子进程fork一个孙进程后退出,那么孙进程被init接管,孙进程结束后,init会回收。不过子进程的回收估计还要自己做。
作为daemon,4相对简单一些,是较为常用的做法;
如果不希望程序自动转后台,3是比较好的方法;
系统中system调用太多,懒得改了。用方法4给封装一下system,到时候替换一下就行了。
int System(const char * cmdstring)
{
pid_t pid;
int status;
if(cmdstring == NULL){
return (1);
}
if((pid = vfork())<0){
status = -1;
}
else if(pid == 0){
//printf("process forked. pid=%d ppid=%d\n", getpid(), getppid());
pid_t cpid;
if ((cpid = vfork()) < 0) {
_exit(127);
} else if (cpid == 0) {
//printf("process forked. pid=%d ppid=%d\n", getpid(), getppid());
execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);
_exit(127); //子进程正常执行则不会执行此语句
} else {
//printf("after fork a process, Process[%d] exit.\n", getpid());
exit(0);
}
}
else{
while(waitpid(pid, &status, 0) < 0){
if(errno != EINTR){
status = -1;
break;
}
}
//printf("###################child %d exit###################\n", pid);
}
return status;
}
急着版本发布,有问题了再修改吧。先修改了再说吧
(3更简单)
533

被折叠的 条评论
为什么被折叠?



