waitpid和SIGCHLD信号回收僵尸进程

对于多进程而言,父进程一般需要跟踪子进程的退出状态。因此当子进程结束运行时,内核不会立即释放该进程的进程表的表项。以满足父进程后续对子进程退出的信息查询(死后验尸),当然前提是父进程还在运行。在子进程结束之后,父进程读取其退出状态之前,我们称该子进程处于僵尸态(用户空间已经被释放,其不能被调度)。

先介绍两个系统调用函数:

 #include <sys/types.h>
 #include <sys/wait.h>

pid_t wait(int *status);// wait是一个阻塞函数,等待回收子进程,如果没有子进程则返回-1.成功返回子进程的id

pid_t waitpid(pid_t pid, int *status, int options);
// status 即是传入参数又是传出参数,通过传入地址来保存进程退出值,这里是int类型32位一部分是用来保存进程退出值,一部分是用来保存信号值。
//wait函数的阻塞显然不是服务器所期望的,而waitpid函数可以解决这个问题
<pre name="code" class="cpp">第一个参数:
< -1 回收指定进程组内的任意子进程
-1 回收任意子进程
0 回收和当前调用waitpid一个组的所有子进程
> 0 回收指定ID的子进程

options
WNOHANG没有子进程结束,立即返回(非阻塞)
WUNTRACED如果子进程由于被停止产生的SIGCHLD, waitpid则立即返回
WCONTINUED如果子进程由于被SIGCONT唤醒而产生的SIGCHLD, waitpid则立即返回
获取status
WIFEXITED(status)子进程正常exit终止,返回真
WEXITSTATUS(status)返回子进程正常退出值
WIFSIGNALED(status)子进程被信号终止,返回真
WTERMSIG(status)返回终止子进程的信号值
WIFSTOPPED(status)子进程被停止,返回真
WSTOPSIG(status)返回停止子进程的信号值
WIFCONTINUED(status)子进程由停止态转为就绪态,返回真
 
#include<stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include<unistd.h>
int main()
{
	pid_t pid=fork();
	if(pid<0)
	{
		perror("fork");
		return 0;
	}
	
	if(pid==0)
	{
		printf("child process pid:%d \n",getpid());
		sleep(10);
		return 12;
	}
	else
	{
		int status=0;
		printf("parent process pid:%d \n",getpid());
		printf("wait pid:%d \n",wait(&status)); //wait是阻塞的
		printf("process exit value:%d \n",WEXITSTATUS(status));//print 进程的退出值
		printf("signal value:%d \n",WTERMSIG(status));//print 信号值 kill -9 杀死子进程就会打出9
	}
	return 0;
}

目前有两种方法来进行回收僵尸进程1.wait阻塞方式2.waitpid的轮询模式。这两种方式都会导致父进程无法干别的事。

接下来我们将来讲述如何使用SIGCHLD处理僵尸进程

SIGCHLD的产生条件默认处理方式是忽略

1.子进程终止时候

2.子进程收到SIGSTOP信号停止时

3.子进程处于停止态,接受SIGCONT后唤醒时

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


void sig_child(int num)
{
	int status;
	pid_t pid;
	while((pid=waitpid(-1,&status,WNOHANG))>0)//回收子进程非阻塞方式
	{
        if (WIFEXITED(status))
		{
             printf("child %d exit %d\n", pid, WEXITSTATUS(status));
		}else if(WIFSIGNALED(status))
		{
			printf("child %d cancel signal %d\n", pid, WTERMSIG(status));
		}
			 
	}
}
int main()
{
	pid_t pid;
	int i=0;
	for(i=0;i<4;i++)
	{
		if((pid=fork())==0) //如果是子进程则直接退出循环,由父进程fork出四个子进程
	    {
		   break;
	    }
		else if(pid<0)
		{
			perror("fork error ");
			return 0;
		}
	}
	
	if(pid==0)
	{
		printf("child process pid:%d \n",getpid());
		sleep(20);
		return 10;
	}
	else
	{
		struct sigaction sigact;  
		sigact.sa_handler=sig_child;//信号响应函数
		sigact.sa_flags=0;//选择第一种函数类型(根据 struct sigaction 结构体来的)
		sigemptyset(&sigact.sa_mask);//置0,SIGCHLD 默认是忽略的
		sigaction(SIGCHLD,&sigact,NULL);  //注册信号
		while(1)
		{
			printf("parent id is:%d \n",getpid());
			sleep(1);
		}
	
	}
	return 0;
}
另打开一个终端输入 kill -9 2229,可以看到进程id为2229是被信号杀死的。



  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值