fork()
我们知道现代的fork()是已经应用了COW-Copy On Write的,父进程在fork()后创建的子进程先对父进程的数据段,堆段,栈段中的各页采用写时复制,令这些段的页表项指向父进程相同的物理内存页,并将这些页标记为只读!之后内核会通过写保护发现所有父进程或是子进程对页面的修改企图,并为将要修改的页面创建拷贝; 内核会将新的页面拷贝分配给遭到内核发现修改的进程; 之后父子进程可以分别修改各自的页拷贝而不再相互影响!
例子:
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<string.h>
#include<stdlib.h>
static int idata = 1;//全局数据段
int main(int argc, char* argv[]){
int istack = 1;//栈段
pid_t childPid;
switch(childPid = fork()){
case -1:
fprintf(stderr,"fork Failed!");
exit(EXIT_FAILURE);
break;
case 0:
istack *=4;
idata *=4;
break;
default:
sleep(5);
break;
}
printf("PID=%d (%s) idata=%d istack=%d\n", childPid, (childPid==0)?"child":"parent",idata,istack);
exit(EXIT_SUCCESS);
}
这个例子会发现,子进程对于栈段,数据段的修改是不会影响到父进程的(父进程不可见!);
vfork()
因为早期的fork()是完全对父进程内存空间的复制,在fork()后立即执行exec()的情况下是非常浪费的!出于这个原因引入了vfork(),它无需为子进程复制虚拟内存页或是页表,而是子进程共享父亲进程的内存,直到成功执行了exec()或是调用_exit()退出!而且在子进程结束之前会阻塞父进程的执行!注意这里和fork()的区别,fork()也是创建时父子进程共享内存,但是是对内存进行只读保护; 而vfork()是在遇到exec()才结束共享,是专门针对立即exec()的场景的!因此会出现子进程的修改父进程可见的怪异现象!