上個博客講了如何使用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函數相關的使用,後面會繼續介紹進程相關的其它函數使用方法,感謝您的閱讀,如有不對的地方,歡迎指出謝謝。