日期:2014-05-16  浏览次数:20946 次

关于vfork()函数对父进程空间的处理
在APUE上关于VFORK讲的太少,看了一遍又一遍还是看不出门道。只知道vfork()调用后子进程先起来。是在父进程环境上运行的。如果在子进程中对父进程的一个变量写操作。则该变量在父进程也已经改变(因为是共享的)。
但是最近遇到一个问题,就是uClinux上只有vfork,程序需要vfork()结合pipe()。
在父子进程中各自关闭不需要的 读端,写端。然后进行通信,发现和 fork()的结果是一样的。就很郁闷了。按理说在子进程中关闭写端,那么在父进程中该写端也被关闭了(不是共享吗)。但是事实上并没有。
还有 ,不但是管道,对于打开的文件也是如此。
[code=C/C++][/code]
 8 int main()
  9 {
 10 int n;
 11 int open_fd;
 12 int fd[2];
 13 pid_t pid;
 14 char line[16];
 15 open_fd = open("local.c", O_RDONLY);
 16 if(pipe(fd) < 0) {
 17 perror("pipe error!");
 18 exit(-1);
 19 }
 20 if((pid = vfork()) < 0) {
 21 perror("cannot vfork!");
 22 exit(-1);
 23 }
 24 else if(pid == 0) {
 25 printf("open_fd=%d\n", open_fd); 
 29 close(open_fd);
 32 
 33 }
 34 else {
 35 printf("open_fd=%d\n", open_fd);
 40 n = read(open_fd, line, 16);
 41 printf("n=%d\n", n);
 42 write(STDOUT_FILENO, line ,n);
 43  
 44 }
 45 
 46 exit(0);
 47 }
实际上父进程也读到了东西,这跟用fork()的结果是一样的。
敢问各位大虾。vfork()对文件描述符做了特殊处理了吗?在子进程中已经关闭了该描述符,但是在父进程还可以引用(肯定是父进程中的该文件描述符)。按照程序执行结果
open_fd=3
open_fd=3
n=12
hello world

可以推断在父子进程都有指向该文件的描述符,并且子进程中的描述符是父进程中的 拷贝,关闭其中一个对另一个没有影响。
他们指向了同一个文件。

但是这样,不就和vfork()相矛盾了吗?
 

------解决方案--------------------
你这个和vfork没有关系;和变量本身有关第;虽然你关了文件描述符,但变量所指向的值并没有清除,还是原来的值,当然不会有变化,比如

int fd = open("./test.data",O_RDWR);
...
printf("%d\n",fd);
close(fd);
printf("%d\n",fd);

两次打印出来的值一样,大多数时候都是这样,一样;当然,前提是没有其它变量在进行相关运算
------解决方案--------------------
尽量不要使用vfork
父进程会被子进程阻塞

不过似乎linux下 fork与vfork实现是一样的 这个可以参见apue

------解决方案--------------------
那你就看看uClinux下vfork手册吧,APUE讲的是通用的特性,至于具体的特性,得看具体平台的手册;按理说,其次,文件描述符所指向的文件也有一个计数标志; 这个计数标志相当于文件硬链接的计数标志,每创建一次硬链接,文件计数标志加1,只有当这个计数标志为0时,才能真正删除文件,同样地,父子进程之间共享的文件描述符所指向的文件表项也有一个计数标志,每打开一次或者fork一次,这个计数标志就加1,只有当这个计数标志为0时,才真正关闭文件表项中的记录; 这样做是出于效率和安全性的考虑,你想啊,每次fork或者都会拷贝父进程的文件描述符;如果每次都去创建一个文件表项,有点浪费;vfork也一样。虽然共享地址空间,但打开一次,计数器应该加1;看看内核源码吧