天天看點

程序之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程序即僵屍程序

[email protected]:/home/samba/share/mywork/test/wait$ sudo gcc -o wait wait.c 
[email protected]:/home/samba/share/mywork/test/wait$ ./wait 
I am parent process pid = 4160
I am child process pid = 4161
child process exit...

[email protected]:/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>


[email protected]:/proc/4160$ cd ../4161
[email protected]:/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捕捉,這時就不會成為僵屍程序

[email protected]:/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

[email protected]:/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傳回的結果
[email protected]:/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終止程序函數,或者其它程序發送信号終止的結果
[email protected]:/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頂替作為子程序的父程序

[email protected]:/home/samba/share/mywork/test/wait$ ./wait &
[1] 13017
[email protected]:/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
[email protected]:/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
[email protected]:/home/samba/share/mywork/test/wait$ cd /proc/13018
[email protected]:/proc/13018$ cat status 
Name:	wait_1
Umask:	0002
State:	S (sleeping)
Tgid:	13018
Ngid:	0
Pid:	13018
PPid:	1     //init成為父程序
           

以上就是關于避免僵屍程序産生的方式,以為wait函數相關的使用,後面會繼續介紹程序相關的其它函數使用方法,感謝您的閱讀,如有不對的地方,歡迎指出謝謝。

繼續閱讀