进程总是处在下面三种状态的一种:
(1)运行(2)停止(3)终止。
进程终止的原因:
(1)收到一个默认行为是终止进程的信号 (2)从主程序中返回 (3)调用exit函数
一个终止了但是没有被回收的进程成为僵死进程。进程一般是通过父进程进行回收,如果父进程没有回收它的僵死的子进程就终止了,那么内核就安排init进程来回收它们。init进程的PID为1,并且实在系统初始化的时候由内核创建的。僵死进程虽然没有运行,但是依然消耗系统的存储器资源,父进程回收已终止的子进程是,内核将子进程的退出状态传递给父进程,然后抛弃已经终止的进程。
父进程通过调用waitpid函数来等待它的子进程终止或者停止。每个waitpid函数对应一个等待集合。
#include <sys/types.h>
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int *status, int options);
如果pid>0,等待集合就是一个单独的子进程,它的进程ID等于pid,
如果pid=-1,等待集合就是由父进程所有的子进程组成。
option默认为0,决定waitpid的操作,默认情况下,waitpid挂起调用进程的执行,直到它的等待集合中的一个子进程终止。waitpid返回已经终止的子进程的PID,并将这个已终止的子进程从系统中去除。
如果staus非空,则waitpid会在参数status中放上关于导致返回的子进程的状态信息。可以通过如下的几个宏定义,判断status的状态信息。
(1)WIFEXITED(status):如果子进程通过调用exit或者返回正常终止,则返回真
(2)WEXITSTATUS(status):返回一个正常终止的子进程的退出状态
(3)WIFSIGNALED(status):如果子进程接收到一个默认行为是终止进程的信号而终止的,则返回真
(4)WTERMSIG(status):如果子进程是因为信号的原因终止,则返回信号的编号
(5)WIFSTOPPED(status):如果引起返回的子进程当前是被停止的,则返回真
(6)WSTOPSIG(status):返回引起子进程终止的信号的数量
错误条件:
如果调用进程没有子进程,则waitpid返回-1,并且设置errno为ECHILD
如果waitpid函数被一个信号中断,则返回-1,并设置errno为EINTR
例城:
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/wait.h>
#include<stdlib.h>
#include<errno.h> /**errno定义在errno.h中 */
#include<string.h> /**strerror定义在string.h中 */
#define N 2
int main()
{
int status, i;
pid_t pid[N],retpid;
for(i=0;i<N;i++)
{
if((pid[i]=fork())==0)
{
exit(100+i);
}
}
i = 0;
while((retpid=waitpid(pid[i++],&status,0))>0)
{
if(WIFEXITED(status))
{
printf("child %d terminated normally with exit status=%d\n",retpid,WEXITSTATUS(status));
}
else
{
printf("child %d terminated abnormally\n",retpid);
}
}
if(errno != ECHILD)
{
fprintf(stderr,"fork error :%s\n",strerror(errno));
}
exit(0);
}
运行结果:
child 4423 terminated normally with exit status=100
child 4424 terminated normally with exit status=101