进程之wait/waitpid使用

上个博客讲了如何使用fork简单的创建一个新的进程,本篇文章将讲下如何避免僵尸进程的产生,僵尸进程的产生就是因为子进程退出时没有父进程替它"收尸"即没有获取子进程的状态信息,一般我们可以使用wait或者waitpid函数来进行处理

下面的代码示例演示了子进程如何成为僵尸进程的过程

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>


void main(void)
{
	pid_t pid;

	if (0 > (pid = fork()))
	{
		printf("fork error\n");
		return;
	}
	else if (0 == pid)
	{
		printf("I am child process pid = %ld\n", (long)getpid());
		sleep(1);
		printf("child process exit...\n");
		return;
	}
	else
	{
		printf("I am parent process pid = %ld\n", (long)getpid());
		while (1)
		{
			sleep(1);
		}
	}
	return;
}

运行结果:4160的子进程4161成为了Z进程即僵尸进程

mcchen@mcchen-virtual-machine:/home/samba/share/mywork/test/wait$ sudo gcc -o wait wait.c 
mcchen@mcchen-virtual-machine:/home/samba/share/mywork/test/wait$ ./wait 
I am parent process pid = 4160
I am child process pid = 4161
child process exit...

mcchen@mcchen-virtual-machine:/home/samba/share/mywork/test/wait$ ps
   PID TTY          TIME CMD
  3736 pts/4    00:00:00 bash
  4160 pts/4    00:00:00 wait
  4161 pts/4    00:00:00 wait <defunct>


mcchen@mcchen-virtual-machine:/proc/4160$ cd ../4161
mcchen@mcchen-virtual-machine:/proc/4161$ cat status 
Name:	wait
State:	Z (zombie)
Tgid:	4161
Ngid:	0
Pid:	4161
PPid:	4160
TracerPid:	0
Uid:	1000	1000	1000	1000
Gid:	1000	1000	1000	1000

下面将使用wait函数来获得子进程的状态

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

void main(void)
{
	pid_t pid;
	int statloc;

	if (0 > (pid = fork()))
	{
		printf("fork error\n");
		return;
	}
	else if (0 == pid)
	{
		printf("I am child process pid = %ld\n", (long)getpid());
		sleep(1);
		printf("child process exit...\n");
		return;
	}
	else
	{
		printf("I am parent process pid = %ld\n", (long)getpid());
		pid = wait(&statloc);
		printf("pid = %ld has exit\n", (long)pid);
		while(1)
		{
			sleep(1);
		}
	}
	return;
}

下面的结果显示,子进程11633正常退出,并且状态信息被父进程11632捕捉,这时就不会成为僵尸进程

mcchen@mcchen-virtual-machine:/home/samba/share/mywork/test/wait$
I am parent process pid = 11632
I am child process pid = 11633
child process exit...
pid = 11633 has exit

mcchen@mcchen-virtual-machine:/home/samba/share/mywork/test/wait$ ps
   PID TTY          TIME CMD
  3736 pts/4    00:00:00 bash
 11632 pts/4    00:00:00 wait
 11638 pts/4    00:00:00 ps

下面的实例演示了和wait相关的三个获取终止状态的函数

WIFEXITED(status) :若为正常终止子进程返回的状态,则为真,使用WEXITSTATUS(status)来获取状态

WIFSIGNALED(status) :若为异常终止子进程返回的状态,则为真,对于这种情况,可执行WTERMSIG(status)获取使子进程终止的信号编号

WIFSTOPPED(status) :若为当前暂停子进程的返回的状态,则为真,对于这种情况,可执行WSTOPSIG(status)获取使子进程暂停的信号编号

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
void main(void)
{
	pid_t pid;
	int statloc;

	if (0 > (pid = fork()))
	{
		printf("fork error\n");
		return;
	}
	else if (0 == pid)
	{
		printf("I am child process pid = %ld\n", (long)getpid());
		sleep(1);
		printf("child process exit...\n");
		return; //直接正常返回,或者使用exit(1) 
		//abort(); //异常返回,或者其它进程发信号终止该子进程
	}
	else
	{
		printf("I am parent process pid = %ld\n", (long)getpid());
		pid = wait(&statloc);
		if (WIFEXITED(statloc))
		{
			printf("normal termination, exit status = %d\n", WEXITSTATUS(statloc));
		}
		else if (WIFSIGNALED(statloc))
		{
			printf("abnormal termination, signal number = %d\n", statloc);
		}
		else if (WIFSTOPPED(statloc))
		{
			printf("child stopped, signal number = %d\n", WSTOPSIG(statloc));
		}
		printf("pid = %ld has exit\n", (long)pid);
		while(1)
		{
			sleep(1);
		}
	}
	return;
}

正常return返回的和发送信号导致异常返回的结果不一样,如下

//正常使用return 或者exit返回的结果
mcchen@mcchen-virtual-machine:/home/samba/share/mywork/test/wait$ 
I am parent process pid = 12570
I am child process pid = 12571
child process exit...
normal termination, exit status = 0
pid = 12571 has exit

//使用abort终止进程函数,或者其它进程发送信号终止的结果
mcchen@mcchen-virtual-machine:/home/samba/share/mywork/test/wait$ 
I am parent process pid = 12580
I am child process pid = 12581
child process exit...
abnormal termination, signal number = 134
pid = 12581 has exit

上面讲的可以使用wait等待子进程的状态信息避免僵尸进程的产生,还有另一种方式就是父进程在子进程退出前先退出,这样的话因为子进程没有了父进程,系统就讲init进程作为子进程的父进程,而init永远不会退出,同时会在子进程退出后为其收尸,所以子进程便不会成为僵尸进程,下面将演示父进程先退出,init成为父进程

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
void main(void)
{
	pid_t pid;
	int statloc;
	int i = 0;

	if (0 > (pid = fork()))
	{
		printf("fork error\n");
		return;
	}
	else if (0 == pid)
	{
		printf("I am child process pid = %ld\n", (long)getpid());
		while (i++ < 5)
		{
			sleep(1); //让父进程先退出
		}
		printf("child process exit...\n");
		return; //直接正常返回,或者使用exit(1) 
	}
	else
	{
		printf("I am parent process pid = %ld\n", (long)getpid());
		printf("parent process exit...\n");
		return;
	}
	return;
}

结果是父进程先退出,init顶替作为子进程的父进程

mcchen@mcchen-virtual-machine:/home/samba/share/mywork/test/wait$ ./wait &
[1] 13017
mcchen@mcchen-virtual-machine:/home/samba/share/mywork/test/wait$ 
I am parent process pid = 13017
parent process exit...           //父进程先退出
I am child process pid = 13018
child process exit...            //子进程后退出
[1]+  Exit 23                 ./wait
mcchen@mcchen-virtual-machine:/home/samba/share/mywork/test/wait$ ps
   PID TTY          TIME CMD
 11735 pts/4    00:00:01 bash
 13018 pts/4    00:00:00 wait
 13019 pts/4    00:00:00 ps
mcchen@mcchen-virtual-machine:/home/samba/share/mywork/test/wait$ cd /proc/13018
mcchen@mcchen-virtual-machine:/proc/13018$ cat status 
Name:	wait_1
Umask:	0002
State:	S (sleeping)
Tgid:	13018
Ngid:	0
Pid:	13018
PPid:	1     //init成为父进程

以上就是关于避免僵尸进程产生的方式,以为wait函数相关的使用,后面会继续介绍进程相关的其它函数使用方法,感谢您的阅读,如有不对的地方,欢迎指出谢谢。

发布了33 篇原创文章 · 获赞 7 · 访问量 8345

猜你喜欢

转载自blog.csdn.net/muchong123/article/details/103266515