通过调用fork创建了一个子进程,通过返回值来判断,但始终无法并不知道结束顺序,比如下面在两个进程中,最后都分别执行message内容,并sleep 1秒钟,不过子进程执行了3次,而父进程仅仅执行一次,就会出现奇怪的现象~!
#include <stdio.h> #include <unistd.h> #include <stdlib.h> int main(){ pid_t pid; char *message; int n; if ((pid = fork()) < 0) { printf("fork failed...\n"); exit(1); } else if (pid == 0){ message = "child now..."; n = 3; } else { message = "parent now..."; n = 1; } for(; n > 0; n--){ puts(message); sleep(1); } return 0; }
编译执行结果如下:
lihui@2015 ~ $ ./a.exe child now... parent now... child now... lihui@2015 ~ $ child now...
很莫名其妙的,第一次打印了1次父进程和2次子进程,这时候结束了,可立马在什么都没做的情况下,shell命令行又跳出来了一行子进程的打印信息
也就是说这里运行的时候,子进程并没有执行完毕,而父进程已经结束了,具体说是在子进程打印完它的所有消息之前就结束了,所以就显得有些乱
有时候我们希望知道子进程何时结束,并且能够通过父进程等待子进程的结束,可以调用wait函数:
#include <sys/wait.h> pid_t wait(int *status);
wait系统调用会暂停父进程直到它的子进程结束为止,这个系统调用返回的是子进程的pid,此时应该是已经结束运行的子进程的pid,而且允许父进程了解子进程的退出状态,也就是子进程main函数返回的值或者是子进程exit函数的退出码,如果status不是空指针,状态信息也会被写入它所指向的位置;通过sys/wait.h里定义的宏解释状态信息:
WIFEXITED(status) 如果子进程正常结束,它返回一个非零值 WEXITSTATUS(status) 如果WIFEXITED非零,它返回子进程的退出码 WIFSIGNALED(status) 如果子进程因为一个未捕获的信号而终止,它返回一个非零值 WTERMSIG(status) 如果WIFSIGNALED非零,它返回一个信号代码 WIFSTOPPED(status) 如果子进程意外终止,它返回一个非零值 WSTOPSIG(status) 如果WIFSTOPPED非零,它返回一个信号代码
如此一来,想要父进程在执行完之后,等待子进程先执行完,自己再结束,可以加入最后一段主进程的等待过程:
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/wait.h> int main(){ pid_t pid; char *message; int n; if ((pid = fork()) < 0) { printf("fork failed...\n"); exit(1); } else if (pid == 0){ message = "child now..."; n = 3; } else { message = "parent now..."; n = 1; } for(; n > 0; n--){ puts(message); sleep(1); } if (pid != 0){ int status; pid_t child_pid; child_pid = wait(&status); printf("child %d finished...\n", child_pid); if (WIFEXITED(status)) printf("child exited with code %d\n", WEXITSTATUS(status)); else printf("child abnormally...\n"); } return 0; }
如此一来,编译,执行,就再也不会出现主进程结束了,子进程还冒出来打印信息的现象:
lihui@2015 ~ $ ./a.exe child now... parent now... child now... child now... child 5964 finished... child exited with code 0