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是被信号杀死的。

版权声明:欢迎转载,如有不足之处,恳请斧正。

时间: 2024-10-11 21:25:00

waitpid和SIGCHLD信号回收僵尸进程的相关文章

一、进程与信号之僵尸进程

孤儿进程:父进程被终结,子进程成为孤儿进程,被init进程接管 僵尸进程:子进程被终结,内存未被释放,形成僵尸进程 #include <unistd.h> #include <stdlib.h> #include <stdio.h> int main(void) { pid_t pid; pid=fork(); if(pid<0) { printf("fork error"); exit(1); } else if(pid ==0) { //终

[转] linux下的僵尸进程处理SIGCHLD信号

什么是僵尸进程? 首先内核会释放终止进程(调用了exit系统调用)所使用的所有存储区,关闭所有打开的文件等,但内核为每一个终止子进程保存了一定量的信息.这些 信息至少包括进程ID,进程的终止状态,以及该进程使用的CPU时间,所以当终止子进程的父进程调用wait或waitpid时就可以得到这些信息. 而僵尸进程就是指:一个进程执行了exit系统调用退出,而其父进程并没有为它收尸(调用wait或waitpid来获得它的结束状态)的进程. 任何一个子进程(init除外)在exit后并非马上就消失,而是

linux下的僵尸进程处理SIGCHLD信号

什么是僵尸进程? 首先内核会释放终止进程(调用了exit系统调用)所使用的所有存储区,关闭所有打开的文件等,但内核为每一个终止子进程保存了一定量的信息.这些信息至少包括进程ID,进程的终止状态,以及该进程使用的CPU时间,所以当终止子进程的父进程调用wait或waitpid时就可以得到这些信息. 而僵尸进程就是指:一个进程执行了exit系统调用退出,而其父进程并没有为它收尸(调用wait或waitpid来获得它的结束状态)的进程. 任何一个子进程(init除外)在exit后并非马上就消失,而是留

UNIX高级环境编程(9)进程控制(Process Control)- fork,vfork,僵尸进程,wait和waitpid

本章包含内容有: 创建新进程 程序执行(program execution) 进程终止(process termination) 进程的各种ID ? 1 进程标识符(Process Identifiers) 每个进程都有一个唯一的标识符,进程ID(process ID). 进程的ID是可重用的,如果一个进程被终止,那么它的进程ID会被系统回收,但是会延迟使用,防止该进程ID标识的新进程被误认为是以前的进程. 三个特殊ID的进程: Process ID 0:调度者进程,内核进程. Process

僵尸进程

In UNIX System terminology, a process that has terminated,but whose parent has not yet waited for it, is called a zombie. 在UNIX 系统中,一个进程结束了,但是他的父进程没有等待(调用wait / waitpid)他, 那么他将变成一个僵尸进程. 但是如果该进程的父进程已经先结束了,那么该进程就不会变成僵尸进程, 因为每个进程结束的时候,系统都会扫描当前系统中所运行的所有进

第7章 进程关系(1)_守护、孤儿和僵尸进程

1. 守护.孤儿和僵尸进程 (1)守护进程 ①守护进程(daemon)是生存期长的一种进程.它们常常在系统引导装入时启动,在系统关闭时终止. ②所有守护进程都以超级用户(用户ID为0)的优先权运行. ③守护进程没有控制终端 ④守护进程的父进程都是init进程(1号进程). (2)孤儿进程:父进程先结束,子进程就成为孤儿进程,会由1号进程(init进程)领养. [编程实验]产生孤儿进程 //process_orphen.c #include <unistd.h> #include <std

php多进程 防止出现僵尸进程

对于用PHP进行多进程并发编程,不可避免要遇到僵尸进程的问题. 僵尸进程是指的父进程已经退出,而该进程dead之后没有进程接受,就成为僵尸进程(zombie)进程.任何进程在退出前(使用exit退出) 都会变成僵尸进程(用于保存进程的状态等信息),然后由init进程接管.如果不及时回收僵尸进程,那么它在系统中就会占用一个进程表项,如果这种僵尸进程过多,最后系统就没有可以用的进程表项,于是也无法再运行其它的程序. 方法一: 父进程通过pcntl_wait和pcntl_waitpid等函数等待子进程

一起聊聊 Linux 系统中的僵尸进程

Linux 系统中僵尸进程和现实中僵尸(虽然我也没见过)类似,虽然已经死了,但是由于没人给它们收尸,还能四处走动.僵尸进程指的是那些虽然已经终止的进程,但仍然保留一些信息,等待其父进程为其收尸.僵尸进程如何产生的?如果一个进程在其终止的时候,自己就回收所有分配给它的资源,系统就不会产生所谓的僵尸进程了.那么我们说一个进程终止之后,还保留哪些信息?为什么终止之后还需要保留这些信息呢?一个进程终止的方法很多,进程终止后有些信息对于父进程和内核还是很有用的,例如进程的ID号.进程的退出状态.进程运行的

TCP/IP 网络编程 (抄书笔记 3) -- 僵尸进程和多任务并发服务器

TCP/IP 网络编程 (抄书笔记 3) – 僵尸进程和多任务并发服务器 TCP/IP 网络编程 (抄书笔记 3) – 僵尸进程和多任务并发服务器 Table of Contents 僵尸进程的产生 避免僵尸进程 信号 多任务的并发服务器 僵尸进程的产生 子进程先退出, 父进程没有退出 ==> 僵尸进程 父进程先退出, 子进程没有退出 ==> 子进程被 0 号进程回收, 不会产生僵尸进程 pid_t pid = fork(); if (pid == 0) { // child printf(&