【原创】《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
- 【原创】《Linux高级程序设计》杨宗德著- 进程管理与程序开发 - fork和vfork函数
- 【原创】《Linux高级程序设计》杨宗德著 - 进程管理与程序开发 - exec和system函数
- 【原创】《Linux高级程序设计》杨宗德著 - 进程管理与程序开发 - 孤儿进程和僵死进程
- 【原创】《Linux高级程序设计》杨宗德著 - 进程管理与程序开发 - 进程资源及属性
- 【原创】《Linux高级程序设计》杨宗德著 - 进程管理与程序开发 - 回收进程用户/内核资源
- 【原创】《Linux高级程序设计》杨宗德著 - 进程管理与程序开发 - 守护进程
- 【原创】《Linux高级程序设计》杨宗德著 - 进程管理与程序开发 - System V进程间通信基础
- 【原创】《Linux高级程序设计》杨宗德著 - 进程管理与程序开发 - Linux常见信号及处理
- 【原创】《Linux高级程序设计》杨宗德著 - 进程管理与程序开发 - 安装信号与捕捉信号
- 【原创】《Linux高级程序设计》杨宗德著 - 进程管理与程序开发 - 信号集与屏蔽信号
- 【原创】《Linux高级程序设计》杨宗德著 - 进程管理与程序开发 - 管道
- 【原创】《Linux高级程序设计》杨宗德著 - 进程管理与程序开发 - 等待信号
- 【原创】《Linux高级程序设计》杨宗德著 - 进程管理与程序开发 - 信号应用实例
- 【原创】《Linux高级程序设计》杨宗德著 - 进程管理与程序开发 - 信号量通信机制
- 【原创】《Linux高级程序设计》杨宗德著 - 进程管理与程序开发 - 共享内存
- 【原创】《Linux高级程序设计》杨宗德著 - 进程管理与程序开发 - System V进程间通信之消息队列
- Linux应用程序开发之 多进程程序设计(一) fork()和vfork()
- 【原创】《Linux高级程序设计》(杨宗德著)--- Linux进程存储管理
- Android在代码中打开Wifi、移动网络和GPS
- Spring MVC 3.0 深入及对注解的详细讲解
- 机器学习相关
- 第9周 项目6-5 任务分配
- css 样式用法的累积
- 【原创】《Linux高级程序设计》杨宗德著- 进程管理与程序开发 - fork和vfork函数
- POJ - 2096 Collecting Bugs(概率dp)
- web网页
- shell脚本命令,统计文件行数
- Apache DBUtils使用总结
- Mybatis3简单使用(PostgreSQL)
- Java中8种基本数据类型及其默认值
- VC 获取CPU ID
- 全局变量的定义方法