讲到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
嘎嘎, 这是我们期望的结果.