【原创】《Linux高级程序设计》杨宗德著- 进程管理与程序开发 - fork和vfork函数

来源:互联网 发布:c# 初始化数组 编辑:程序博客网 时间:2024/05/18 11:24

 

【原创】《Linux高级程序设计》杨宗德著- 进程管理与程序开发 - fork和vfork函数

 

1. 创建进程

fork函数调用成功后,其子进程会复制父进程的几乎所有信息(除PID等信息),主发复制父亲进程的代码段、数据段、BSS、堆、栈(关于进程结构参阅本书第3章)、打开的文件描述符(但共用同一个文件表项)。另外,子进程从父进程继承下列属性:实际用户/组号、有效用户/组号以及保留的用户/组号、进程组号、环境变量、对文件的执行时关闭标志、信号处理方式设置、信号掩码、当前工作目录、根目录、文件模式创建掩码、文件大小限制等信息。
代码实例:

/*************************************************************************> File Name: fork_basic.c> Author: Geng> Mail: genglut@163.com> Created Time: Thu 30 Oct 2014 10:19:00 PM CST ************************************************************************/#include<stdio.h>#include<unistd.h>#include<sys/types.h>int main(int argc,char *argv[]){pid_t pid;if((pid=fork())==-1)printf("fork error");printf("Geng!\n");return 0;}

运行结果:

$ ./fork_basic Geng!Geng!

从运行结果可以看出,fork函数后的代码在子进程中也被执行。实际上,其他代码也在子进程的代码段中,只是子进程执行位置为fork返回的位置,其之前的代码无法执行罢了。

2. 子进程对父进程文件流缓冲区的处理

在创建子进程时,子进程的用户空间将复制父进程的用户空间所有信息,显然,也包含流缓冲区的内容。如果流缓冲区中有临时信息,则同样复制到子进程的用户空间流缓冲区中。

示例代码如下:

/*************************************************************************> File Name: streamfork.c> Author: Geng> Mail: genglut@163.com> Created Time: Thu 30 Oct 2014 10:36:05 PM CST ************************************************************************/#include <stdio.h>#include <unistd.h>#include <stdlib.h>int main(int argc,char *argv[]){pid_t pid;printf("before fork,have enter\n");printf("before fork,no enter:pid=%d\t",getpid());pid=fork();if(pid==0)printf("\nchild,after fork:pid=%d\n",getpid());elseprintf("\nparent,after fork:pid=%d\n",getpid());}

运行结果:

$ ./a.out before fork,have enterbefore fork,no enter:pid=5397parent,after fork:pid=5397before fork,no enter:pid=5397child,after fork:pid=5398

从运行结果可以看出,如果流缓冲区中有临时信息,则同样复制到子进程的用户空间流缓冲区中。

3. 子进程对父进程打开的文件描述符的处理

fork函数创建子进程后,子进程将复制父进程的数据段、BSS段、代码段、堆空间、栈空间和文件描述符,而对于文件描述符关联的内核文件表项(即struct file结构),则是采用共享的方式。

示例代码如下:

/*************************************************************************> File Name: datah.c> Author: Geng> Mail: genglut@163.com> Created Time: Thu 30 Oct 2014 11:20:37 PM CST ************************************************************************/#include <sys/types.h>#include <stdio.h>#include <unistd.h>#include <fcntl.h>#include <string.h>#include <stdlib.h>int main(int argc,char *argv[]){    pid_t pid;    int fd;    int i=1;    int status;    char *ch1="hello";    char *ch2="world";    char *ch3="IN";    if((fd=open("test.txt",O_RDWR|O_CREAT,0644))==-1)    {perror("parent open");exit(EXIT_FAILURE);    }    if(write(fd,ch1,strlen(ch1))==-1)    { perror("parent write");exit(EXIT_FAILURE);    }        if((pid=fork())==-1)    {perror("fork");exit(EXIT_FAILURE);    }    else if(pid==0)    {i=2;printf("in child\n");printf("i=%d\n",i);if(write(fd,ch2,strlen(ch2))==-1)    perror("child write");return 0;    }    else    {sleep(1);printf("in parent\n");printf("i=%d\n",i);if(write(fd,ch3,strlen(ch3))==-1)    perror("parent,write");wait(&status);return 0;    }}

运行结果:

$ ./a.out in childi=2in parenti=1$ cat test.txt helloworldIN

通过文件test.txt可以看出,父子进程共同对同一文件操作,且写入数据不交叉覆盖,说明父子进程共享文件偏移,因此,共享文件表项。

对于变量i,在子进程中进行了第二次赋值(i=2),其结果为2,而父进程中i的值不变,显然,父子进程各自拥有这一变量的副本,互不影响。

4. vfork测试全局数据段与BSS段的使用策略

fork和vfork有一定的区别,fork是复制一个父进程的副本,拥有自己独立的代码段、数据段及堆栈空间。而vfork是共享父进程的代码及数据段。

示例程序:

#include<unistd.h>#include<error.h>#include<sys/types.h>#include<stdio.h>#include<stdlib.h>int glob=6;int main(){int var;pid_t pid;var=88;printf("in beginning:\tglob=%d\tvar=%d\n",glob,var);if((pid=vfork())<0){perror("vfork");exit(EXIT_FAILURE);}else if(pid==0){printf("in child,modify the var:glob++,var++\n");glob++;var++;printf("in child:\tglob=%d\tvar=%d\n",glob,var);_exit(0);}else{printf("in parent:\tglob=%d\tvar=%d\n",glob,var);return 0;}}

运行结果:

$ ./a.out in beginning:glob=6var=88in child,modify the var:glob++,var++in child:glob=7var=89in parent:glob=7var=89

由结果可以看出,父子进程共享数据空间,因此,打印的信息是一致的。

如果将上述代码中的vfork换成fork,其他代码不做修改,重新编译执行后,结果如下:

8$ ./a.out in beginning:glob=6var=88in parent:glob=6var=88in child,modify the var:glob++,var++in child:glob=7var=89

由上可知,父子进程打印的信息不一致。即父子进程各自拥有独立的地址空间。

5. 子函数调用vfork创建子进程

首先看运行结果:

$ ./a.out 1:child pid=7087,ppid=70863:child pid=7087,ppid=70862:parent pid=7086,ppid=3363段错误 (核心已转储)

示例代码:

#include<stdio.h>#include<unistd.h>#include<stdlib.h>void test(){    pid_t pid;    pid=vfork();    if(pid==-1)    {       perror("vfork");       exit(EXIT_FAILURE);    }    else if(pid==0)    {          printf("1:child pid=%d,ppid=%d\n",getpid(),getppid());       return;    }    else       printf("2:parent pid=%d,ppid=%d\n",getpid(),getppid());}void fun(){     int i;   int buf[100];   for(i=0;i<100;i++)       buf[i]=0;   printf("3:child pid=%d,ppid=%d\n",getpid(),getppid());}int main(){   pid_t pid;   test();   fun(); }

出现段错误的原因,见教材197页。

6. fork和vfork的区别

参考链接:

http://blog.csdn.net/buaalei/article/details/5348382

http://blog.sina.com.cn/s/blog_7673d4a5010103x7.html 

原文链接:http://blog.csdn.net/geng823/article/details/40656741

0 0
原创粉丝点击