1,几个概念
- 僵死进程(其实就是zombie,僵尸):一个进程已经终止了,但是它的父进程又还没有对他进行善后(比如通过wait获取该子进程的终止状态,释放子进程占用的资源),那么这个已死的进程就叫僵死进程。话说这个都是老子替儿子善后啊,白发人送黑发人。。。。。
- 收养:如果一个进程还没终止,但是它的父进程已经终止了,这时候他就成孤儿了。那这个进程终止后岂不无人善后,一定变僵尸??所以系统会自动的让init进程(pid=1)收养这个孤儿,以保证每一个进程都有父进程,不会死后变僵尸。
- 退出状态:exit()的输入参数或者return后面跟的数字,就是退出状态。
- 终止状态:exit函数会调用_exit()系统调用,在这里退出状态会变成终止状态。后面会介绍一个宏定义WEXITSTATUS,其可以通过终止状态恢复出退出状态。
2,函数原型
#include<sys/wait.h>
pid_t wait(int* statloc)
成功,返回子进程的pid;失败,返回0.
函数执行的效果:避免僵尸产生
这个函数在父进程中执行,一直等待其子进程退出。有任意一个子进程退出,wait就返回子进程的pid。并且,如果输入参数statloc不为空指针,则其能获得子进程的终止状态。注意,终止状态并不等于exit的输入参数(退出状态)。终止状态含有退出状态的信息。如果在wait执行前已经有子进程退出了,则wait不用等待,马上获取到该子进程的退出状态并返回。如果一直没有子进程退出,则wait就一直等待,阻塞。
一个典型的使用方法是这样的:
if (wait(&status) != pid){
printf("wait error!");
exit(1);
}
3,一些配套的宏定义
我们用wait可以获取到子进程终止时的终止状态status。可是status只是一个int。怎么通过这个int来获取信息呢?
有几个以WIF(我怀疑是wait if的意思。。。)开头的宏定义可用。它们和wait函数在同一个头文件下。
- WIFEXITED(status) , 如果子进程是正常终止,则返回true。这种情况下可以通过WEXITSTATUS(status)获取退出状态
- WIFSIGNALED(status),如果子进程异常退出,例如abort退出或分母为0等等,则其为true。此时,可以通过WTERMSIG(status)获取子进程终止的信号编号。同时,有些系统里定义了WCOREDUMP,可以用来确定这个异常退出有没有产生coredump文件。 用法就是WCOREDUMP(status),为true就是产生了。
- stop什么的现在不懂,以后再说吧。
4,例子
//获取终止状态的信息,并打印
void pre_exit(int status)
{
printf("pre_exit, status = %d\n", status);
if(WIFEXITED(status)) //正常退出
{
printf("normal termination, exit status = %d\n", WEXITSTATUS(status));
}
else if (WIFSIGNALED(status)) //异常退出,包括abort()或其他
{
printf("abnormal termination, signal number = %d%s\n",WTERMSIG(status),
#ifdef WCOREDUMP
WCOREDUMP(status) ? " (core file generated)" : "");
#else
"");
#endif
}
else if(WIFSTOPPED(status)) //stop??
{
printf("child stopped, signal number = %d\n", WSTOPSIG(status));
}
}
int main(void){
pid_t pid;
int status;
// 1,正常退出
if((pid = fork()) < 0 ) { //小于0代表fork出错
printf("fork error!");
exit(1);
} else if (pid == 0) { //等于0代表子进程
exit(7); //exit的输入参数为退出状态
}
//用wait获取子进程的退出状态,获取不到就阻塞,一直等着
//如果子进程已经终止了,那它马上就能获取到,马上返回
//返回值为子进程的pid
if (wait(&status) != pid){
printf("wait error!");
exit(1);
}
pre_exit(status);
// 2, abort
if((pid = fork()) < 0 ) {
printf("fork error!");
exit(1);
} else if (pid == 0) {
abort(); //用abort终止子进程
}
if (wait(&status) != pid){
printf("wait error!");
exit(1);
}
pre_exit(status);
//3, 分母为0
if((pid = fork()) < 0 ) {
printf("fork error!");
exit(1);
} else if (pid == 0) {
status /= 0; //这个异常会导致子进程退出
}
if (wait(&status) != pid) {
printf("wait error!");
exit(1);
}
pre_exit(status);
//父进程退出
exit(0);
}
执行效果是:
➜ code ./study_linux
pre_exit, status = 1792
normal termination, exit status = 7
pre_exit, status = 134
abnormal termination, signal number = 6 (core file generated)
pre_exit, status = 136
abnormal termination, signal number = 8 (core file generated)
可以看到,
第一次,正常退出,退出状态就是我们传递给exit的参数7。
第二次,abort退出,会发出SIGABRT信号,也就是6;
第三次,分母为0,crash,信号为8