本帖最后由 蓝蓝的天 于 2016-7-5 18:03 编辑
在早期的实现中,fork没有实现写时拷贝机制,而是直接对父进程的数据段,堆和栈
进行完全拷贝,效率十分低下。很多程序在fork一个子进程后,会紧接着执行E x e c
家族函数,这更是一种浪费。所以BSD引入了vfork。既然fork之后会执行E x e c函数,拷贝
父进程的内存数据就没有意义了,所以引入的vfork压根就不会拷贝父进程的内存数据,
而是直接共享。再后来Linux引入了写时拷贝的机制,其效率提高了很多,这样一来,
vfork其实就可以退出历史舞台了。
vfork会创建一个子进程,该子进程会共享父进程的内存数据,而且系统将保证子进程
先于父进程获得调度。子进程也会共享父进程的地址空间,而父进程将被一直挂起,直到
子进程退出或执行e x ec。
注意,vfork之后,子进程如果返回,则不要调用return,而应该使用_exit函数。如果
使用return,就会出现诡异的错误。请看下面的示例代码:
编译:
运行:
调用子进程,如果使用return返回,就意味着main函数返回了,因为栈是父子进程
共享的,所以程序的函数栈发生了变化。main函数return之后,通常会调用exit系的
函数,父进程收到子进程的exit之后,就开始从vfork返回,但是这时整个main函数
的栈都已经不复存在了,所以父进程压根无法执行。于是会返回一个诡异的栈地址。
作为对比,改成用_exit函数返回,代码如下;
编译运行:
可以看到,运行结果正确,也不报错了。
本帖最后由 蓝蓝的天 于 2016-7-5 18:03 编辑
在早期的实现中,fork没有实现写时拷贝机制,而是直接对父进程的数据段,堆和栈
进行完全拷贝,效率十分低下。很多程序在fork一个子进程后,会紧接着执行E x e c
家族函数,这更是一种浪费。所以BSD引入了vfork。既然fork之后会执行E x e c函数,拷贝
父进程的内存数据就没有意义了,所以引入的vfork压根就不会拷贝父进程的内存数据,
而是直接共享。再后来Linux引入了写时拷贝的机制,其效率提高了很多,这样一来,
vfork其实就可以退出历史舞台了。
vfork会创建一个子进程,该子进程会共享父进程的内存数据,而且系统将保证子进程
先于父进程获得调度。子进程也会共享父进程的地址空间,而父进程将被一直挂起,直到
子进程退出或执行e x ec。
注意,vfork之后,子进程如果返回,则不要调用return,而应该使用_exit函数。如果
使用return,就会出现诡异的错误。请看下面的示例代码:
编译:
运行:
调用子进程,如果使用return返回,就意味着main函数返回了,因为栈是父子进程
共享的,所以程序的函数栈发生了变化。main函数return之后,通常会调用exit系的
函数,父进程收到子进程的exit之后,就开始从vfork返回,但是这时整个main函数
的栈都已经不复存在了,所以父进程压根无法执行。于是会返回一个诡异的栈地址。
作为对比,改成用_exit函数返回,代码如下;
编译运行:
可以看到,运行结果正确,也不报错了。