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

 

【原创】《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());
	else
		printf("\nparent,after fork:pid=%d\n",getpid());
}

运行结果:

$ ./a.out 
before fork,have enter
before fork,no enter:pid=5397	
parent,after fork:pid=5397
before fork,no enter:pid=5397	
child,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 child
i=2
in parent
i=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=6	var=88
in child,modify the var:glob++,var++
in child:	glob=7	var=89
in parent:	glob=7	var=89

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

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

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

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

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

首先看运行结果:

$ ./a.out 
1:child pid=7087,ppid=7086
3:child pid=7087,ppid=7086
2: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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值