僵尸进程和处理方式

本文介绍了在父进程与子进程交互过程中出现的僵尸进程问题及其三种常见解决方案:使用wait和waitpid函数等待子进程结束;利用signal函数为SIGCHLD安装handler;以及忽略SIGCHLD信号让内核自动回收。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int main()
{
	int n;
	int i;
	char *s;
	pid_t pid=fork();
	assert(pid!=-1);
        if(pid == 0)
        {
                n=2;
                s="child";
        }
        else
        {
                n=5;
                s="parent";
        }
        for(i=0;i<n;i++)
        {
                printf("%d,%s\n",getpid(),s);
                sleep(1);
        }
       	return 0;
}


在父程序中用于判断子程序是否结束

僵尸进程
子进程提前于父进程结束,造成无法清理掉pcb和其他系统消耗造成pid的长时间占用(如上图)

如果父进程异常结束时就成了一个孤儿进程交个pid=1 的init作为父进程进行管理收尸;

三种处理方式

⒈父进程通过wait和waitpid等函数等待子进程结束,这会导致父进程挂起问题父进程在wait处会阻塞如果父进程很忙会造成一系列

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <assert.h>
int main()
{
	signal(SIGCHLD,fun);
	char *p=NULL;
	pid_t pid=fork();
	assert(pid!=-1);
	int n=0;
	if(pid==0)
	{
			p="child";
			n=10;
	}
	else
	{
		p="parent";
		n=20;
	}
	int i=0;
	for(;i<n;i++)
	{
			printf("%s\n",p);
			sleep(1);
	}
    if(pid!=0)
    {
	wait();
    }
	return 0;
}

⒉ 如果父进程很忙,那么可以用signal函数为SIGCHLD安装handler,因为子进程结束后, 父进程会收到该信号,可以在handler中调用wait回收。

第二种代码(只要在父进程收到子进程结束的信号时就去处理该信号)

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <assert.h>
void fun(int sig)
{
		printf("sig=%d\n",sig);
		wait();
		signal(SIGCHLD,SIG_DFL);//回复默认
}
int main()
{
	signal(SIGCHLD,fun);
	char *p=NULL;
	pid_t pid=fork();
	assert(pid!=-1);
	int n=0;
	if(pid==0)
	{
			p="child";
			n=10;
	}
	else
	{
		p="parent";
		n=20;
	}
	int i=0;
	for(;i<n;i++)
	{
			printf("%s\n",p);
			sleep(1);
	}
	return 0;
}

⒊ 如果父进程不关心子进程什么时候结束,那么可以用signal(SIGCHLD,SIG_IGN) 通知内核,自己对子进程的结束不感兴趣,那么子进程结束后,内核会回收, 并不再给父进程发送信号。

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <assert.h>
int main()
{
	signal(SIGCHLD,SIG_IGN);
	char *p=NULL;
	pid_t pid=fork();
	assert(pid!=-1);
	int n=0;
	if(pid==0)
	{
			p="child";
			n=10;
	}
	else
	{
		p="parent";
		n=20;
	}
	int i=0;
	for(;i<n;i++)
	{
			printf("%s\n",p);
			sleep(1);
	}
	return 0;
}


 还就是fork两次,父进程fork一个子进程,然后继续工作,子进程fork一 个孙进程后退出,那么孙进程被init接管,孙进程结束后,init会回收。不过子进程的回收 还要自己做。相比与第一种的好处就是父进程不用等因为子进程在父进程运行时很快就结束了;
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <assert.h>
int main()
{
	char *p=NULL;
	pid_t pid=fork();
	assert(pid!=-1);
	int n=0;
	if(pid==0)
	{
			pid_t pid=fork();
			if(pid==0)
			{
				p="child";
				n=5;
			}
			else
			{
					printf("%d",getpid());
					exit(0);//使他提前结束孙进程交给pid=1;
			}
	}
	else
	{
		p="parent";
		n=20;
	}
    wait(NULL);
	int i=0;
	for(;i<n;i++)
	{
			printf("pid=%d,%s\n",getpid(),p);
			sleep(1);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值