父进程通过
wait
或waitpid
函数来获取子进程的退出状态,并且彻底杀死这个进程,清理这个进程的所有资源。如果不这么做,子进程会变成一个僵尸进程,长时间占用系统内存,造成类似内存泄漏的问题。
wait()
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
参数:输出型参数,获取子进程的退出状态,不关心可以设置为NULL;
返回值:成功返回被等待进程的 pid, 失败返回 -1。
当一个进程终止时,内核就会向其父进程发送 SIGCHLD
异步(即在任意时刻内核都可以向父进程发送)信号。父进程既可以选择忽略该信号,也可以提供一个信号处理函数,对该信号的默认动作是忽略。
那么父进程调用 wait
之后会发生什么?
- 如果没有运行完成的子进程,则父进程会阻塞等待,直到有一个子进程结束,则 wait 函数返回;
- 如果有一个或多个子进程结束,则 wait 直接返回,即只要收到 SIGCHLD 信号,则wait 就会返回;
- 如果该进程没有子进程,则 wait 就会失败,返回 -1。
如果 status
参数不为空,则它里面保存了 子进程的退出状态,我们可以通过几个来获取子进程的退出状态信息。
实际上 status
在不同情况下有不同的含义,它的内容大概如下:
看下面这份代码:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
int main()
{
pid_t pid = fork();
if(pid < 0){
perror("fork");
return 1;
}
else if(pid > 0){//father
printf("father start!\n");
int status;
int ret = wait(&status);
if(ret > 0 && (status & 0xff) == 0){//正常退出
printf("exit code: %d\n", (status>>8)&0xff);
}else{//异常退出
printf("sig code: %d\n", status&0x7f);
}
printf("father end\n");
}else{//child
printf("child start!\n");
printf("child end\n");
exit(99);
}
return 0;
}
它的运行结果如下:
可以看到子进程正常退出,而我们取得 status
的高八位正是子进程的退出码。我们在通过异常信号终止子进程,看看 status
的内容。
waitpid
pid_t waitpid(pid_t pid, int *status, int option);
返回值:
成功返回子进程 pid;
如果设置了WNOHANG
, 则当父进程没有发现已经结束的进程,则它不会阻塞等待,而是直接返回0;
调用中出错返回-1,errno 会被设置;
当 pid 所指示的进程不存在或不是该进程的子进程,则会出错返回,errno会被设置为ECHILD。
参数:
- pid==-1,等待任意一个子进程,pid == 0 等待组 id 等于调用者组 id 的任意一个进程,pid > 0 等待进程id与参数pid相等的进程,pid<-1, 等待子进程id与 pid 绝对值相等的进程。
- status:正常退出时,高八位表示退出码,异常退出时,低七位表示终止信号,可以用宏
WIFEXITED(status)
提取退出状态,当为正常退出时,该宏为真,宏WEXITSTATUS(status)
用来查看正常退出时的退出码,我们也可以通过位运算查看status的内容信息;- option:
WNOHANG
,当子进程没有结束时,父进程返回0,即不会阻塞式等待。
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
int main()
{
pid_t pid = fork();
if(pid < 0){
perror("fork");
return 1;
}
else if(pid > 0){//father
printf("father start!\n");
int status;
int ret = waitpid(-1, &status, WNOHANG);//设置WNOHANG选项
if(ret > 0 && (status & 0xff) == 0){
printf("ret: %d\n", ret);
printf("exit code: %d\n", (status>>8)&0xff);
}else if (ret == 0){
printf("no child finish\n");
}
else{
printf("ret: %d\n", ret);
printf("sig code: %d\n", status&0x7f);
}
printf("father end\n");
}else{//child
printf("child start!\n");
sleep(100);
printf("child end\n");
exit(99);
}
return 0;
}
运行结果:
当设置了 WNOHANG
选项后,父进程没有等待子进程而是直接返回0。
——完!
【作者:果冻:http://blog.csdn.net/jelly_9】