讲到fork, 一个经典的例子如下:
if ((pid = fork()) == 0) {
printf("in child %d\n", getpid());
} else if (pid > 0) {
printf("in parent\n");
} else {
perror("fork");
exit(0);
}
现在, 我要创建5个进程, 每个进程都打印出自己的pid, 写下如下代码:
- #include <stdio.h>
- #include <stdlib.h>
- #define N_PROCESS 5
- int main()
- {
- pid_t pid[N_PROCESS];
- int i;
- /* create child process */
- for (i = 0; i < N_PROCESS; i++) {
- if ((pid[i] = fork()) == 0) {
- printf("in child %d\n", getpid());
- } else if (pid[i] > 0) {
- printf("in parent\n");
- }
- }
- return 0;
- }
看似没有问题, 编译运行, 结果令人惊讶:
- in parent
- in parent
- in parent
- in parent
- in parent
- in child 11799
- in parent
- in parent
- in parent
- in parent
- in child 11799
- in parent
- in parent
- in parent
- in child 11807
- in parent
- in parent
- in parent
- in child 11803
- in parent
- in parent
- in parent
- in parent
- in parent
- in child 11805
- in child 11799
- in parent
- in child 11804
- in parent
- in parent
- in child 11799
- in parent
- in parent
- in child 11806
- in child 11808
- in parent
- in parent
- in parent
- in child 11803
- in child 11809
- in parent
- in parent
- in child 11802
- in parent
- in parent
- in child 11799
- in child 11801
- in parent
- in parent
- in parent
- in child 11799
- in parent
- in child 11804
- in parent
- in child 11811
- in child 11799
- in child 11801
- in parent
- in child 11815
- in parent
- in parent
- in parent
- in child 11802
- in child 11812
- in parent
- in child 11799
- in child 11801
- in child 11813
- in parent
- in parent
- in parent
- in child 11800
- in parent
- in parent
- in parent
- in child 11799
- in parent
- in child 11804
- in child 11810
- in child 11817
- in parent
- in parent
- in child 11802
- in child 11812
- in child 11819
- in child 11799
- in child 11801
- in parent
- in parent
- in child 11816
- in parent
- in parent
- in child 11802
- in parent
- in child 11814
- in child 11799
- in child 11801
- in parent
- in child 11815
- in child 11818
- in parent
- in child 11800
- in parent
- in child 11822
- in parent
- in parent
- in child 11800
- in parent
- in parent
- in child 11824
- in child 11799
- in child 11801
- in child 11813
- in parent
- in child 11823
- in parent
- in child 11800
- in child 11820
- in parent
- in parent
- in parent
- in child 11800
- in parent
- in child 11822
- in child 11825
- in child 11799
- in child 11801
- in child 11813
- in child 11821
- in parent
- in parent
- in child 11800
- in child 11820
- in parent
- in child 11828
- in child 11799
- in child 11801
- in child 11813
- in child 11821
- in child 11826
- in parent
- in child 11800
- in child 11820
- in child 11827
- in child 11829
数一数, 程序创建了31个子进程! 怪哉, 哪里出问题了呢?
仔细分析一下, 第一次fork调用时, i = 0, fork完成后, 子进程和父进程拥有相同的存储,
即两者的 i = 0,然后父进程执行parent代码段, 打印 "in parent", 子进程执行child代码
段, 打印自己的pid. 关键是, 到了这里, 子进程没有退出, 处于for循环中, 于是子进程接着
执行 i = 1 时的for循环, 子进程执行fork, 又创建子进程, 这样就产生孙子进程. 按照这种
步骤, 孙子进程又会创建子进程....稍微分析一下, 可以得到递推公式,如果想创建n个子进程,
将执行 2^n - 1次fork调用并产生2^n-1个子进程, 真是子子孙孙无穷尽也...
可见, 问题的关键是, 终止子进程继续执行for循环, 修改代码:
- #include <stdio.h>
- #include <stdlib.h>
- #define N_PROCESS 5
- int main()
- {
- pid_t pid[N_PROCESS];
- int i;
- /* create child process */
- for (i = 0; i < N_PROCESS; i++) {
- if ((pid[i] = fork()) == 0) {
- printf("in child %d\n", getpid());
- exit(0); /* 让子进程退出 */
- } else if (pid[i] > 0) {
- printf("in parent\n");
- }
- }
- return 0;
- }
运行结果如下:
- in parent
- in child 12037
- in parent
- in parent
- in child 12039
- in child 12038
- in parent
- in child 12040
- in parent
- in child 12041
这次只创建了5个进程, 但parent代码段执行了5次, 不符合我们的要求, 再改:
- #include <stdio.h>
- #include <stdlib.h>
- #define N_PROCESS 5
- int main()
- {
- pid_t pid[N_PROCESS];
- int i;
- /* create child process */
- for (i = 0; i < N_PROCESS; i++) {
- if ((pid[i] = fork()) == 0) {
- printf("in child %d\n", getpid());
- exit(0); /* 让子进程退出 */
- }
- }
- printf("in parent\n");
- return 0;
- }
运行结果如下:
- in child 12072
- in parent
- in child 12074
- in child 12075
- in child 12073
- in child 12076
嘎嘎, 这是我们期望的结果.