最近看《Unix环境高级编程》,其中有讲到创建子线程用fork的函数调用,这个函数特别之处是调用一次,返回两次,分别为0和pid,这里假定每次创建都是成功的。
为啥返回两次呢,而且值不一样呢?
返回两次是系统调用的实现,需要查看fork是如何实现的,这里面就比较复杂了,鄙人现在不懂。
返回值不同,创建进程返回新生进程的id值,新生进程返回0,每一个进程的父进程是确定的,可以通过getppid来获取,但子进程的个数可以不止一个,所以父进程中返回新生进程的id值。
然后需要注意的是fork和vfork的区别,fork一个新生进程,(进程--资源分配的最小单位哦,亲),新生进程和父进程是共享代码段的,但数据段是父进程的拷贝,而vfork后,新生进程和父进程共享代码段也共享数据段,不是拷贝。
当然fork之后,是新生进程先执行,还是父进程先执行,取决于进程调度,调度顺序不一定。
好了,废话扯了一堆,来看看下面的一道面试题目:
微软的一个选择题目,问输出的"-"有多少个?2个 4个 6 个 还是8个?
1 #include<stdio.h>
2 #include<sys/types.h>
3 #include<unistd.h>
4 int main(int argc ,char **argv)
5 {
6 int i;
7 for(i=0;i<2;i++)
8 {
9 fork();
10 printf("-");
11 }
12 return 0;
13 }
按照书上面讲的来分析一下,假定初始化的进程id为IDNUM,
<1>
当他执行到9的时候,成功创建了一个新生进程,假定id为IDNUM+1
这时IDNUM和IDNUM+1分别打印了一次,个数为2,执行拷贝数据,所以新生进程的i值现在为0
然后执行for循环的第3部分,这时IDNUM 和IDNUM+1的i值都变为了1
<2>
执行for循环的第2部分,再次执行到9行,进程为IDNUM的进程产生新的进程,假定为IDNUM+2
进程为IDNUM+1的进程产生新的进程,假定为IDNUM+3
这时新生进程IDNUM+2和新生进程IDNUM+3执行数据拷贝他们的i值现在为1
这时每个进程都打印了1次,所以个数为2+4=6个
这之后执行for循环体第3部分,现在所以的进程的i值都变为了2
<3>
执行for循环的第2部分,条件不成立,for循环结束,之后执行return 0.由于没有写信号处理函数,系统负责SIGEND SIGCHID的处理,这时候执行抛弃?还是啥,不记得了,但系统会负责资源的回收,是否会产生僵死进程呢,等下不防试验一下。看看有没有被挂到1号进程上面的新进程。理论完了,看看分析对不对,下面的部分是实验所得。
实验部分:
说明:使用的系统未ubuntu 10.04LTS版本64位,2.6.32内核
实验一
把上述用vi编辑好后,采用gcc -o fork fork.c 编译,运行之后得到的结果是:
是不是很奇怪呢,打印出了8个-,不是之前我yy的6个。先别急,毕竟这本书粗略的看了一下,对linux也还没入门好吧
等下进一步分析。
实验二
接下来的一个题目非常有意思为啥这么说,因为不仔细看,还以为题目出重复了
1 #include<stdio.h>
2 #include<sys/types.h>
3 #include<unistd.h>
4 int main(int argc ,char **argv)
5 {
6 int i;
7 for(i=0;i<2;i++)
8 {
9 fork();
10 printf("-\n");
11 }
12 return 0;
13 }
和上面的题目唯一的区别就是在第10行的输出部分,加入了回车换行,仍然问输出的“-”有多少个?2个 4个 6个 还是8个?
也不墨迹了,直接跑起来,下面是实验结果:
这次貌似对了6个“-”,和我之前yy的结果是一样的,但别得意,为啥这么大的区别,到底是为什么呢?缓冲区?引用计数?信号处理?
蛋在这个时候已经不复存在。
还望高人指点一二。
那就在深究一下好了,还是实验,通过加入getpid和getppid来看看输出。
实验三
在实验二的基础上,稍微改动一下好了
ok,运行结果呢:
跟我上面yy的基本上符合,5303号进程为shell进程id吧,6493为shell为执行体第一加载的进程id,
输出的内容会不一定,因为每次加载时分配的进程id是按照未分配的进程id往上加的,且进程之间执行顺序的先后,和系统进程调用环境有关,
贴个证据:
除了shell的pid是相同的,最后有一个进程的父id挂为了1,有孤儿进程出现,何谓孤儿进程,就是创建它的父进程已经消亡,子进程还没运行完毕
这时系统会把这些进程挂到1号进程上去,成为1号进程的子进程
实验结果就是:和我yy的过程是一致的,下面查看下系统的进程,可以通过/proc目录,也可以用ps命令查看一下,不过发现找不到进程id为6584这样的进程,
说明这些进程最后还是被系统给销毁了
但这到底是为什么呢,为什么呢,希望高人指点一二,《Unix高级编程》有时间必须看上好几遍哦~~~~~5555555555555555