使用SIGCHLD信号完成对子进程的回收

1、SIGCHLD信号

1.1 信号作用

子进程退出后,内核会给它的父进程发送SIGCHLD信号,父进程收到这个信号后可以对子进程进行回收。
使用SIGCHLD信号完成对子进程的回收可以避免父进程阻塞等待而不能执行其他操作,只有当父进程收到SIGCHLD信号之后才去调用信号捕捉函数完成对子进程的回收,未收到SIGCHLD信号之前可以处理其他操作。

1.2 产生条件

  • 子进程结束时
  • 子进程收到SIGSTOP信号
  • 子进程停止时,收到SIGCONT信号

2、练习

要求:父进程创建出三个子进程,然后令父进程捕获SIGCHLD信号完成对子进程的回收。

2.1 代码实现

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>

//SIGCHLD信号处理函数
void waitChild(int sign)
{	
	pid_t wpid;
	while(1)
	{
		wpid = waitpid(-1,NULL,WNOHANG); //调用waitpid函数回收子进程
		if(wpid>0)
		{
			printf("child is quit,wpid==%d\n",wpid);
		}
		else if(wpid==0)
		{
			printf("child is living,wpid==%d\n",wpid);
		}
		else if(wpid<0)
		{
			printf("no child is living,wpid==%d\n",wpid);
			break;
		}
	}
}

int main()
{	
	int i= 0;
	//将SIGCHLD信号阻塞
	sigset_t mask;
	sigemptyset(&mask);
	sigaddset(&mask,SIGCHLD);
	sigprocmask(SIG_BLOCK,&mask,NULL);
	
  	//循环创建三个子进程
	for( i = 0;i<3;i++)
	{
	    //pid_t fork(void)
	    pid_t pid = fork();
	    if(pid<0)
		{
			perror("fork error");
			return -1;
		}
		else if(pid>0)//父进程
		{
			printf("father: pid == [%d],fpid==[%d]\n",getpid(),getppid());
		}
		else if(pid==0) //子进程
		{
			printf("child: pid==[%d],fid==[%d]\n",getpid(),getppid());
			break; //防止子进程循环创建子进程
		}
	}
	//第一个子进程
	if(i==0)
	{
		printf("[%d]:child\n",i);
	} 
	//第二个子进程
	if(i==1)
	{
		printf("[%d]:child\n",i);
	} 
	//第三个子进程
	if(i==2)
	{
		printf("[%d]:child\n",i);
	} 

	//父进程
	if(i==3)
	{
		printf("[%d]:father\n",i);

		//注册SIGCHLD信号处理函数
		struct sigaction act;
		act.sa_handler = waitChild;
		sigemptyset(&act.sa_mask);
		act.sa_flags = 0;
		sleep(5); //保证在信号处理函数注册完成前子进程先退出产生僵尸进程
		sigaction(SIGCHLD,&act,NULL);

		//在注册信号处理函数后解除对SIGCHLD的阻塞
		sigprocmask(SIG_UNBLOCK,&mask,NULL);

		//保证父进程不退出
		while(1)
		{
			sleep(1);
		} 
	} 
	return 0;
}

2.2 注意点

  1. 有可能还未完成信号处理函数的注册三个子进程都退出了。这样会导致僵尸进程的产生。
    解决办法:可以在fork之前先将SIGCHLD信号阻塞,当完成信号处理函数的注册后在解除阻塞。
  2. 当SIGCHLD信号函数处理期间, SIGCHLD信号若再次产生是被阻塞的,而且若产生了多次, 则该信号只会被处理一次, 这样可能会产生僵尸进程。
    解决办法:可以在信号处理函数里面使用while(1)循环回收, 这样就有可能出现捕获一次SIGCHLD信号但是回收了多个子进程的情况,从而可以避免产生僵尸进程。
全部评论

相关推荐

沉淀一会:1.同学你面试评价不错,概率很大,请耐心等待; 2.你的排名比较靠前,不要担心,耐心等待; 3.问题不大,正在审批,不要着急签其他公司,等等我们! 4.预计9月中下旬,安心过节; 5.下周会有结果,请耐心等待下; 6.可能国庆节前后,一有结果我马上通知你; 7.预计10月中旬,再坚持一下; 8.正在走流程,就这两天了; 9.同学,结果我也不知道,你如果查到了也告诉我一声; 10.同学你出线不明朗,建议签其他公司保底! 11.同学你找了哪些公司,我也在找工作。
点赞 评论 收藏
分享
一颗宏心:华为HR晚上过了十二点后还给我法消息。
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务