fork的使用和多次fork产生的一系列问题

2014-11-24 12:36:37 · 作者: · 浏览: 0

看这样一道题:这个程序有几个进程,输出几个'-'

#include 
  
   
#include 
   
     int main() { int i; for(i = 0; i < 2; ++i) { fork(); printf("-"); fflush(stdout); } return 0; }
   
  

要判断几个进程必须知道程序是怎么执行的,子进程是从哪里开始执行?是从程序的开头吗?显然不是,因为我们知道子进程和父进程是共享正文段的,如果子进程从代码段的开始执行,那么当再次执行到fork时又会创建子进程,如果就这样循环下去内存不被耗尽才怪呢。理论上的原因是子进程是父进程的一份副本(包括数据空间,堆,栈等)拷贝,当然也包括程序计数器PC。也就是说子进程要执行的下一条指令就是父进程要执行的下一条指令,所以子进程会从程序段的后面一条语句开始执行。所以右4个进程。接下来要判断输出的次数。结果是6次。程序如果变成如下:

#include 
  
   
#include 
   
     int main() { int i; for(i = 0; i < 2; ++i) { fork(); printf("-"); } return 0; }
   
  

结果会出人意料多2次:输出了8次'-'。

产生这种结果的原因是,C库IO函数都是带缓冲的, fork的时候会stdout的缓冲区也复制

如果没有fflush:
i =0, 2个进程的printf之前缓冲区都为空, printf之后缓冲区printf之后各有一个“-”;
i = 1时, 4个进程printf之前缓冲区都为“-”, printf之后缓冲区各有一个“--”;
在4个进程退出之前,系统会把缓冲区中的内容输入,所以4个"--", 共8个‘-’。

如果有fflush:
i =0, 2个进程的printf之前缓冲区都为空, printf之后缓冲区printf之后各有一个“-”; fflush之后, 2个进程各输出’一个’-‘, 缓冲被清空;
i =1, 4个进程的printf之前缓冲区都为空, printf之后缓冲区printf之后各有一个“-”; fflush之后, 4个进程各输出’一个’-‘, 缓冲被清空;

所以共有2+4=6个‘-’输出。

再看这段代码:

#include 
  
   
#include 
   
     int main() { int i; for(i = 0; i < 2; ++i) { fork(); printf("-\n"); } return 0; }
   
  

输出结果与上述有fflush结果一样。这是因为换行符起了fflush一样的作用,及时刷新了输出缓冲区。

如果我换一种方式运行程序:

$./a.out > std.out

$ cat std.out

结果又变成了8个'-'。

这是因为此时缓冲方式变为全缓冲。系统的默认情况是:当标准输入输出连至终端时,它们是行缓冲的。当将这两个流重定向到普通文件时,它们就变成是全缓冲的,其缓冲区长度是该文件系统优先选用的IO长度(从stat结构中得到st_blksize的值)。