网络编程(32)—— linux中销毁僵尸进程的四种方法

一、wait函数



函数原型:
pid_t wait(int *status);
描述:
wait可以回收任意一个僵尸进程,只要系统中存在僵尸进程,调用一次wait,就会回收一个僵尸进程。
参数说明:
  status - 当子进程结束之后,其进入僵尸进程状态。其状态变化信息被操作系统放置在内存中某一处位置,而status就是这处位置的指针,通过调用wait函数可以获取这部分位置的数据。
获取到数据之后,通过一系列宏可以获取目前操作系统的状态。如:
WIFEXITED(*status)可以判断该进程是否正常结束(main函数通过return或者exit结束),若正常结束返回true,否则返回false。
WEXITSTATUS(*status)用来获取进程正常结束时main函数的返回值,前提是WIFEXITED(status)返回true。
返回值:
返回被结束僵尸状态进程的进程ID。
举例:
int main()
{
	pid_t pid;
	int status;
	pid=fork();
	if(pid==0)
	{
		exit(10);
	}
	else
	{
		pid = wait(&status);
		if(WIFEXITED(status))
		{
			printf("process %d exited,return value = %d\n",pid,WEXITSTATUS(status));
		}
	}
	return 0;
}


缺点:
wait()函数为阻塞函数,也就是说如果操作系统中无僵尸进程的话,程序会一直在wait()处等待,直到出现僵尸进程。


二、waitpid函数



函数原型:
pid_t waitpid(pid_t pid, int *status, int options);
描述:
waitpid()也是用来回收一个僵尸进程,与wait()不同的是,它是非阻塞函数,可以通过设置pid参数回收指定进程ID的僵尸进程,也可以指定回收任意僵尸进程。
参数说明:
status,和wait()函数相同。
pid,指定要回收进程的进程ID,若设为-1,则默认回收任意一个僵尸进程。
options,设置选项,一般情况下设置成WNOHANG,表示不阻塞。
返回值
若存在僵尸进程,返回被结束僵尸状态进程的进程ID;若不存在僵尸进程返回0;若发生错误,返回-1.
举例:
int main()
{
	pid_t pid;
	int status;
	pid=fork();
	if(pid==0)
	{
		sleep(10);
		exit(10);
	}
	else
	{
		while((pid=waitpid(-1,&status,WNOHANG))==0)
		{
			puts("wating ...");
			sleep(2);
		}
		if(WIFEXITED(status))
		{
			printf("process %d exited,return value = %d\n",pid,WEXITSTATUS(status));
		}
	}
	return 0;
}


缺点:
虽然waitpid()不是阻塞函数,但是使用时需要在循环中使用,只有在回收完僵尸进程后才会执行循环之后的代码。


三 signal函数



函数原型:
sighandler_t signal(int signum, sighandler_t handler);
描述:
系统级别的api,向操作系统注册信号和信号处理函数,当操作系统捕获到注册的信号时会调用该信号处理函数。
参数:
signum,向操作系统注册的信号,子进程结束的信号是SIGCHLD。
handler,信号的处理函数,函数原型一般是void handler(int sig)的形式,函数的参数为操作系统捕获的信号,函数的返回值是void
返回值:
返回之前注册的处理该信号的信号处理函数的函数指针。
举例:
void sig_handling(int sig)
{
	int status;
	pid_t pid;
	if(sig==SIGCHLD)
	{
		pid = waitpid(-1,&status,WNOHANG);
		if(WIFEXITED(status))
		{
			printf("process %d exited,return value=%d\n",pid,WEXITSTATUS(status));
		}
	}
}


int main()
{
	pid_t pid;
	signal(SIGCHLD,sig_handling);
	pid=fork();
	if(pid==0)
	{
		exit(11);
	}
	else
	{
		sleep(10000);
	}
	return 0;
}


  请注意:
  1、在信号处理函数sig_handling中,也需要用waitpid()来回收僵尸进程,也就是说signal只是一个注册信号的作用,其本身并没有回收僵尸进程的功能。
  2、一旦用signal注册了信号和信号处理函数,一旦发生该信号,会结束进程的sleep()状态,也就是说在父进程的sleep(10000);将会被打断,不会真的睡10000秒。
 

四 sigaction函数



函数原型:
int sigaction(int signum, const struct sigaction *act,
                     struct sigaction *oldact);
描述:
signum,和signal一样,表示需要注册的信号。
act,sigaction类型的指针,sigaction类型的定义如下:

struct sigaction {
               void     (*sa_handler)(int);
               void     (*sa_sigaction)(int, siginfo_t *, void *);
               sigset_t   sa_mask;
               int        sa_flags;
               void     (*sa_restorer)(void);
           };
  我们进行使用时,只需填写其sa_handler、sa_mask、sa_flags三个成员,sa_handler为信号处理函数,sa_mask使用sigemptyset()函数进行置空,sa_flags直接赋为0。
  oldact,之前注册的  sigaction 类型的指针
返回值:
  成功返回0,失败返回-1
举例:
void sig_handling(int sig)
{
	int status;
	pid_t pid;
	if(sig==SIGCHLD)
	{
		pid = waitpid(-1,&status,WNOHANG);
		if(WIFEXITED(status))
		{
			printf("process %d exited,return value=%d\n",pid,WEXITSTATUS(status));
		}
	}
}


int main()
{
	pid_t pid;
	struct sigaction act;
	act.sa_handler=sig_handling;
	sigemptyset(&act.sa_mask);
	act.sa_flags=0;
	sigaction(SIGCHLD,&act,0);
	pid=fork();
	if(pid==0)
	{
		exit(11);
	}
	else
	{
		sleep(10000);
	}
	return 0;
}


  与signal相比,sigaction函数虽然比较繁琐,但是他的长处在于linux系统多版本的兼容性,而部分版本linux是不支持signal函数的,因此在实际的使用中sigaction的使用范围更广。

Github位置:
https://github.com/HymanLiuTS/NetDevelopment
克隆本项目:
Git clone git@github.com:HymanLiuTS/NetDevelopment.git
获取本文源代码:
git checkout NL32

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值