红联Linux门户
Linux帮助

linux僵尸进程和孤儿进程的简要介绍

发布时间:2016-07-17 10:12:27来源:linux网站作者:Anciety
进程?
即linux(类unix系统)对于运行的程序的一个抽象。
 
谈谈wait和waitpid
wait和waitpid是linux支持的两种system call(系统调用),是父进程获取子进程状态的方式。
头文件:
#include <sys/types.h>
#include <sys/wait.h>
 
函数原型:
pid_t wait (int *status)
pid_t waitpid(pid_t pid,int * status,int options)
 
wait()
wait()会暂时停止目前进程的执行,直到有信号来到或子进程结束。如果在调用wait()时子进程已经结束,则wait()会立即返回子进程结束状态值。子进程的结束状态值会由参数status 返回,而子进程的进程识别码也会一起返回。如果不在意结束状态值,则status可以设成NULL
 
waitpid()
waitpid()会暂时停止目前进程的执行,直到有信号来到或子进程结束。如果在调用waitpid()子进程已经结束,则waitpid()会立即返回子进程结束状态值。子进程的结束状态值会由参数status返回,而子进程的进程识别码也会一起返回。如果不在意结束状态值,则参数status可以设成NULL。参数pid为欲等待的子进程识别码
pid: 当pid为-1时等待任一进程,(相当于和wait差不多),为0则等待和当前进程id一样的,如果为其他负值,则取绝对值,再等待该pid所指定的进程。
options: 为0,或为WNOHANG和WUNTRACED的or组合。
WNOHANG:如果没有任何已经结束的子进程则马上返回,不予以等待。此时返回值为0
WUNTRACED:如果子进程进入暂停执行情况则马上返回,但结束状态不予以理会
 
status状态值
对status状态判断的宏定义:
WIFEXITED(status) 如果子进程正常结束返回的值。取exit或_exit的低8位
WEXITSTATUS(status) 取得子进程exit()返回的结束代码,一般会先用WIFEXITED 来判断是否正常结束才使用此宏
WIFSIGNALED(status) 当子进程因为信号而结束则返回true
WTERMSIG(status) 取得子进程因信号而中止的信号代码,一般会先用WIFSIGNALED 来判断后才使用此宏
WIFSTOPPED(status) 如果子进程处于暂停执行情况则此宏值为真。一般只有使用WUNTRACED 时才会有此情况
WSTOPSIG(status) 取得引发子进程暂停的信号代码,一般会先用WIFSTOPPED来判断后才使用此宏
 
谈谈僵尸进程和孤儿进程
根据以上的资料,我们知道了wait和waitpid的用法,可以说waitpid用来等待特定进程,而wait等待任一进程(waitpid也可以等待任一进程,如果只是需要option的区别的话)。
首先,linux通过父进程来创建子进程,父进程通过wait/waitpid来得到子进程的运行状态,当子进程运行完之后,父进程得到子进程的状态,进行接下来的工作。
那么问题来了,如果父进程一直不愿意调用wait/waitpid呢?
子进程在运行完毕之后是不会完全被销毁掉的,而是会保留一些基础数据:
(包括进程号the process ID,退出状态the termination status of the process,运行时间the amount of CPU time taken by the process等)
僵尸进程则是说的这样一类进程,父进程只管创建,不管回收(一直没有调用wait/waitpid,但是父进程本身又没有结束),子进程就进入僵尸进程状态,标识为Z(zombie)。
孤儿进程则与之对应,说的是父进程不管回收,但是父进程自己死掉了(本身结束了),于是子进程就会被init进程接管,init进程会一直循环wait来将子进程彻底释放掉。
 
危害?影响?
孤儿进程没有较大影响,毕竟该子进程会被init很快就回收掉,但是僵尸进程就不同了,由于进程号有限,在进程号使用完之后,会导致无法创建新的进程,所以一定要注意处理僵尸进程。
 
引用:wait和waitpid函数
(1)wait函数说明
当一个进程正常或异常终止时,内核就向其父进程发送SIGCHLD信号。因为子进程终止是个异步事件,这种信号也是内核向父进程发的异步通知。父进程可以忽略该信号,或者提供一个该信号发生时即被调用执行的函数(信号处理程序)。
父进程同步等待子进程退出时则调用wait函数,此时父进程可能会有如下三种情形:
①阻塞(如果其所有子进程都还在运行)。
②带回子进程的终止状态立即返回(如果已有一个子进程终止,正等待父进程取其终止状态)。
③出错立即返回(如果它没有任何子进程)。
(2)wait与waitpid函数原型
wait(等待子进程的中断和结束)

所需头文件

#include <sys/types.h>

#include <sys/wait.h>

函数说明

wait() 会暂时停止目前进程的执行,直到有信号来到或子进程结束。如果在调用wait()时子进程已经结束,则wait()会立即返回子进程结束状态值。子进程的 结束状态值会由参数status 返回,而子进程的进程识别码也会一起返回。如果不在意结束状态值,则status可以设成NULL

函数原型

pid_t wait (int *status)

函数传入值

status

这里的status 是一个整型指针,是该子进程退出时的状态:

Ÿ   status 若为空,则代表不记录子进程结束状态

Ÿ   status 若不为空,则由status记录子进程的结束状态值

另外,子进程的结束状态可由 Linux中一些特定的宏来测定

函数返回值

成功

返回子进程识别码(PID)

出错

-1,失败原因存于errno中

waitpid(等待子进程的中断和结束)

所需头文件

#include <sys/types.h>

#include <sys/wait.h>

函数说明

waitpid() 会暂时停止目前进程的执行,直到有信号来到或子进程结束。如果在调用waitpid()子进程已经结束,则waitpid()会立即返回子进程结束状态 值。子进程的结束状态值会由参数status返回,而子进程的进程识别码也会一起返回。如果不在意结束状态值,则参数status可以设成NULL。参数 pid为欲等待的子进程识别码

函数原型

pid_t waitpid(pid_t pid,int * status,int options)

函数传入值

 

pid

<-1:等待进程组识别码为pid绝对值的任何子进程

-1: 等待任何子进程,相当于wait()

0:等待进程组识别码与目前进程相同的任何子进程

>0:等待任何子进程识别码为pid的子进程

options

参数options可以为0 或下面的OR 组合

WNOHANG:如果没有任何已经结束的子进程则马上返回,不予以等待。此时返回值为0

WUNTRACED:如果子进程进入暂停执行情况则马上返回,但结束状态不予以理会

函数传出值

status

同wait函数

函数返回值

成功

返回子进程识别码(PID)

使用选项WNOHANG且没有子进程退出返回0

出错

-1,失败原因存于errno中

对status状态判断的宏

说明

子进程的结束状态返回后存于status

宏意义说明

WIFEXITED(status)

如果子进程正常结束返回的值。取exit或_exit的低8位

WEXITSTATUS(status)

取得子进程exit()返回的结束代码,一般会先用WIFEXITED 来判断是否正常结束才能使用此宏

WIFSIGNALED(status)

如果子进程是因为信号而结束则此宏值为真

WTERMSIG(status)

取得子进程因信号而中止的信号代码,一般会先用WIFSIGNALED 来判断后才使用此宏

WIFSTOPPED(status)

如果子进程处于暂停执行情况则此宏值为真。一般只有使用WUNTRACED 时才会有此情况

WSTOPSIG(status)

取得引发子进程暂停的信号代码,一般会先用WIFSTOPPED来判断后才使用此宏

子进程的终止信息存放在一个int变量中,其中包含了多个字段位。用宏定义可以取出其中的每个字段位:如果子进程是正常终止的,WIFEXITED取出的字段值非零,WEXITSTATUS取出的字段值就是子进程的退出状态。如果子进程是收到信号而异常终止的,WIFSIGNALED取出的字段值非零,WTERMSIG取出的字段值就是信号的编号。
(3)wait和waitpid两函数的说明
如果父进程的所有子进程都还在运行,调用wait将使父进程阻塞,而调用waitpid时,如果在options参数中指定WNOHANG可以使父进程不阻塞而立即返回0。
wait等待第一个终止的子进程,而waitpid可以通过pid参数指定等待哪一个子进程。
当pid=-1、option=0时,waitpid函数等同于wait,可以把wait看作waitpid实现的特例。
可见,调用wait和waitpid不仅可以获得子进程的终止信息,还可以使父进程阻塞等待子进程终止,起到进程间同步的作用。如果参数status不是空指针,则子进程的终止信息通过这个参数传出,如果只是为了同步而不关心子进程的终止信息,可以将status参数指定为NULL。
waitpid函数提供了wait函数没有提供的三个功能:
①waitpid等待一个特定的进程,而wait则返回任一终止子进程的状态 。
②waitpid提供了一个 wait的非阻塞版本,有时希望取得一个子进程的状态,  但不想进程阻塞。
③waitpid支持作业控制。
(3)wait函数使用实例
wait.c源代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
pid_t pid;
int status,i;
if(fork()==0){
printf("This is the child process pid =%d\n",getpid());
exit(5);
}else{
sleep(1);
printf("This is the parent process,wait for child...\n");
pid=wait(&status);
i=WEXITSTATUS(status);
printf("child pid =%d, exit status=%d\n",pid,i);
}
return 0 ;
}
编译 gcc wait.c –o wait。
执行 ./wait,执行结果如下:
This is the child process pid =6904
This is the parent process ,wait for child...
child pid =6904, exit status=5
(4)waitpid函数使用实例
waitpid.c源代码如下:
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
pid_t pid;
pid = fork();
if (pid < 0) {
perror("fork failed");
exit(1);
}
if (pid == 0) {  //子进程
int i;
for (i = 3; i > 0; i--) {
printf("This is the child\n");
sleep(1);
}
exit(3);
} else {   //父进程
int stat_val;
waitpid(pid, &stat_val, 0);  /*阻塞等待子进程*/
if (WIFEXITED(stat_val))
printf("Child exited with code %d\n", WEXITSTATUS(stat_val));
else if (WIFSIGNALED(stat_val))
printf("Child terminated abnormally, signal %d\n", WTERMSIG(stat_val));
}
return 0;
}
编译 gcc waitpid.c –o waitpid。
执行 ./waitpid,执行结果如下:
This is the child
This is the child
This is the child
Child exited with code 3
摘录自《深入浅出Linux工具与编程》
 
本文永久更新地址:http://www.linuxdiyf.com/linux/22447.html