僵尸进程的产生和清理

僵尸进程的产生

通俗的讲就是子进程死了,但是父进程还没有给它收尸,此时子进程就成了僵尸进程。

所谓的子进程死了,实际就是指子进程的退出,包括调用exit时的正常退出,或者被kill命令用信号查杀后的异常退出。
那么父进程如何给子进程收尸呢?在父进程中调用wait或waitpid接收子进程退出的状态,清理掉子进程的task_struct,释放子进程的PID。

僵尸进程的处理

子进程一旦成为了僵尸进程后就无法通过KILL来处理,是无法被杀死的,这时候可以通过杀死僵尸进程的父进程的方法来清理掉子进程。

父进程先结束,也就是父进程被杀死了,子进程依然存活,此时子进程被托管给init进程,由init进程回收子进程。这种情况下的子进程称为孤儿进程。

简单的代码验证

#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main(void){
	pid_t pid, wait_pid;
	int status;

	pid = fork(); //创建一个子进程 

	if(pid == -1){
		printf("create new process failed \n");
		exit(1);
			
	}else if(pid == 0){
		printf("child process id :%ld \n",(long)getpid());
		pause(); //令子进程进入睡眠状直到信号被中断
		exit(0);
	}else{
		printf("parent process id : %ld\n",(long)getpid());
	#if 1
		while(1);
	#else 
		do{
			wait_pid = waitpid(pid,&status,WUNTRACED | WCONTINUED);
			//WIFEXITED 非0 表示进程正常结束
			//WEXITSTATUS 获取进程退出状态exit的参数
			//WIFSIGNALED 非0 表示进程异常结束
			//WTERMSIG(staus) 获取进程退出的信号编号
			if(WIFEXITED(status))
				printf("child procees:%d is exit by %d \n",pid,WEXITSTATUS(status));
			if(WIFSIGNALED(status))
				printf("child procees:%d is killed  by signal %d \n",pid,WTERMSIG(status));
		}while(!WIFEXITED(status) && !WIFSIGNALED(status));
		exit(0);
	#endif
	}

}

上述代码编译 gcc test1.c -pthread -o test,然后运行test,结果如下。
在这里插入图片描述
ps au查看进程状态,可以看到可以看到父进程60305,子进程60306。
僵尸进程的产生和清理_第1张图片
此时此时选择用kill -2 60306,杀死子进程60306,然后ps au查看所有进程。
僵尸进程的产生和清理_第2张图片
此时,60306成了僵尸进程,进程状态z+,而这时主进程转态R+,从代码中也可以看到主进程一直处于while循环中,没有任何的wait和waitpid操作。

修改宏定义为#if 0 ,然后编译运行test。得到如下运行结果。
在这里插入图片描述
使用ps au命令查看所有进程运行状态。可以看到父进程60250,子进程60251。
僵尸进程的产生和清理_第3张图片
此时选择用kill -2 60251,杀死子进程60251后并没有使其称为僵尸进程。因为主进程中使用了waitpid处理了子进程,并在获取到子进程退出后,主进程也退出了。此处看到主进程获取到了子进程由于signal 2而产生的退出。
在这里插入图片描述
这时可以看到进程列表中,主进程和子进程都消失了。
僵尸进程的产生和清理_第4张图片

你可能感兴趣的:(linux,系统编程)