进程终止存在两种可能:父进程先于子进程终止和子进程先于父进程终止。
如果父进程在子进程之前终止,则所有子进程的父进程被改为init进程,就是由init进程领养。在一个进程终止时,
系统会逐个检查所有活动进程,判断这些进程是否时正要终止的进程的子进程。如果是,则该进程的父进程ID就改为
1(init的ID),这就保证了每个进程都有一个父进程。
如果子进程在父进程之前终止,系统内核会为每个终止子进程保存一些信息,这样父进程就可以通过调用wait()或
waitpid()函数获得子进程的终止信息。终止子进程保存的信息包括:进程ID,该进程的终止状态,以及该进程所以用的
所有存储空间,关闭其所有打开的文件。一个已经终止但是其父进程尚未对其进行上后处理的进程称为僵尸进程。
当子进程正常或异常终止时,系统内核向其父进程发送SIGCHLD信号;默认情况下,父进程忽略该信号,或者提供
一个该信号发生时即被调用的函数。
父进程可以通过调用wait()或waitpid()函数获得子进程的终止信息。
wait函数如下:
#include<sys/wait.h>
pid_t wait(int *statloc);
参数statloc返回子进程的终止状态(一个整数)。当调用该函数时,如果有一个子进程已经终止,则该函数立即返回,
并释放子进程所有的资源,返回值是终止子进程的ID号;如果当前没有终止的子进程,但有正在执行的子进程,则wait将
阻塞直到所有子进程终止时才返回;如果当前既没有终止的子进程,也没有正在执行的子进程,则返回错误-1。
wait函数的用法如下:
pid_t pid;
int chdestaus;
if ((pid=fork()) > 0){
........//parent process
wait(&chdestaus);
}else if (0 == pid){
..........//child process
exit(0);
}else{
printf("fork() error\n");
exit(0);
}
函数waitpid对等待哪个进程终止及是否采用阻塞操作方式等给出了更多的控制。
waitpid函数如下:
#include<sys/wait.h>
pid_t waitpid(pid_t pid, int *statloc, int option);
waitpid()会暂时停止目前进程的执行,直到有信号来或子进程结束。参数pid指明要等待的子进程的PID,statloc与wait中的
一样,返回子进程的终止状态。
pid值的意义如下:
pid > 0 等待其进程ID等于pid的子进程退出
pid = 0 等待其组ID等于调用进程的组ID的任一子进程
pid < -1 等待其组ID等于pid绝对值的任一子进程
pid = -1 等待任一子进程
参数option可以为0或下面的OR组合:
WNOHANG 如果没有任何结束的子进程则马上返回,不予等待。
WUNTRACED 如果子进程进入暂停执行情况则马上返回,但结束状态不予理会。
子进程的结束状态返回后存于statloc中,底下有几个宏可判别结束情况:
WIFEXITED(statloc) 如果子进程正常结束则为非0值。
WEXITSTATUS(statloc) 取得子进程exit()返回的结束代码,一般会先用WIFEXITED来判断是否正常结束才能使用此宏。
WIFSIGNALED(statloc) 如果子进程是因为信号而结束则此宏值为真
WIFRMSIG(statloc) 取得子进程殷信号而终止的信号代码,一般会先用WIFSIGNALED来判断后才使用此宏。
WIFSTOPPED(statloc) 如果子进程处于暂停执行情况则此宏值为真,一般只使用WUNTRACED时才会有此情况。
WSTOPSIG(statloc) 取得引发子进程暂停的信号代码,一般会先用WIFSTOPPED来判断后才是用此宏。
如果执行成功则返回子进程识别码(PID),如果有错误发生则返回值为-1, 失败原因存于error中。
exit()函数用来终止进程的,返回状态。
#include<stdlib.h>
void exit(int status);
本函数终止调用进程,关闭所有的子进程打开的描述符,向父进程发送SIGCHLD信号,并返回状态,随后父进程即可通过调用wait或waitpid函数获得终止子进程的状态了。