Linux —— fork()与vfork()的区别与联系

fork()与vfork():      

我们在创建一个进程时主要是通过某个已存在的进程来调用fork()或者vfork()函数来实现的,那些已存在的进程是作为系统启动的一部分由内核来创建的。

1.fork函数介绍

#include<unistd.h>

pid_t  fork(void);

功能:创建子进程

正确返回:父进程中返回子进程的pid,子进程返回0.(单调用双返回函数

错误返回:-1

子进程是父进程的一个拷贝,fork()函数子进程拷贝父进程的数据段代码段,但是子进程不与父进程共享数据而是单独分配内存。fork()返回后,父子进程都会从fork函数的下一条语句开始执行,父子进程之间的运行时相互独立的,因此父子进程执行的顺序是不确定的,父进程可以先执行,子进程也可以先执行。

这里用到一个例子来说明:

# include <stdio.h>
# include <sys/types.h>
# include <stdlib.h>
# include <assert.h>
# include <string.h>
# include <unistd.h>

int main()
{
	pid_t pid;
	int count=0;
	pid = fork();
	assert( pid != -1);

	if(pid<0)
	{
		printf("fork is error\n");
	}

	else if(pid == 0)
	{
		printf("\n");
		count++;
		printf("count=%d\n",count);
		printf("I am child process,ID=%d\n",getpid());
	}
	else
	{
		count++;
		printf("count=%d\n",count);
		printf("I am father process,ID=%d\n",getpid());
	}
	return 0;
}

运行结果如下:

可以看出,count的值只是加了1,我们想着执行子进程时count的值应该为2。

但是通过分析可以得知,fork()函数执行之后,子进程拷贝父进程的数据段代码段,此时count++会被父子进程各执行一次,

子进程运行时打印自己数据段中的count+1,父进程与子进程互不影响,父进程执行自己数据段中的count+1,所以才会出现执行出来的结果。 


2.vfork函数介绍

vfork创建进程的主要目的是用exec来执行另外的程序,exec或者exit之前,子进程与父进程之间是数据段共享的。vfork调用中,子进程先执行,父进程挂起,直到子进程调用exec或者exit后,父进程才开始执行。

有一个形象的例子可以描述父子进程的关系:

为什么会有vfork,因为以前的fork 很傻, 它创建一个子进程时,将会创建一个新的地址空间,并且拷贝父进程的资源,而往往在子进程中会执行exec 调用,这样,前面的拷贝工 作就是白费力气了,这种情况下,聪明的人就想出了vfork,它产生的子进程刚开始暂时与父进程共享地址空间(其实就是线程的概念了),因为这时候子进程在父进程的地址空间中 运行,所以子进程不能进行写操作,并且在儿子 霸占”着老子的房子时候,要委屈老子一 下了,让他在外面歇着(阻塞),一旦儿子执行了exec 或者exit 后,相当于儿子买了自己的 房子了,这时候就相 于分家了。
 

通过vfork 函数创建进程,这里同样引入一个计数器:

# include <stdio.h>
# include <sys/types.h>
# include <stdlib.h>
# include <assert.h>
# include <string.h>
# include <unistd.h>

int main()
{
	pid_t pid;
	int count=0;
	pid = vfork();
	assert( pid != -1);

	if(pid<0)
	{
		printf("fork is error\n");
	}
	else if(pid == 0)
	{
		count++;
		printf("count=%d\n",count);
		printf("I am child process,ID=%d\n",getpid());
		_exit(0);
	}
	else
	{
		count++;
		printf("count=%d\n",count);
		printf("I am father process,ID=%d\n",getpid());
	}
	return 0;
}

执行结果如下: 


 

可以看到父进程中count的值为2,这个不难理解,在没有调用_exit(0)之前,父子进程是共享数据段的,此时程序执行时count的值为1。子进程调用了_exit(0)函数后,父进程开始执行,此时父进程数据段中count的值就为1,父进程执行count加1,因此父进程执行完后 count的值就成了2。

总结
区别:
1、fork()用于创建一个新进程。由fork()创建的子进程是父进程的副本。即子进程获取父进程数据空间、堆和栈的副本。父子进程之间不共享这些存储空间的部分。而vfork()创建的进程并不将父进程的地址空间完全复制到子进程中,因为子进程会立即调用exec (或exit)于是也就不会存放该地址空间。相反,在子进程调用exec或exit之前,它在父进程的空间进行。
2、vfork()与fork()另一个区别就是:vfork保证子进程先运行,在它调用exec或exit之后父进程才可能被调度运行。

相同:
1、两者被调用一次,但是返回两次。两次返回的唯一区别是子进程的返回值是0,而父进程的返回值则是新子进程的进程ID。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值