fork和vfork的差异:linux
一、fork是建立一个子进程,并把父进程的内存数据copy到子进程中。c++
vfork是建立一个子进程,并和父进程的内存数据share一块儿。ide
二、vfork是这样的工做的:函数
(1)、保证子进程先执行。优化
(2)、当子进程调用exit()或exec()后,父进程往下执行。spa
三、fork后来采用的优化技术,这样,对于fork后并非立刻拷贝内存,而是只有你在须要改变的时候,才会从父进程中拷贝到子进程中,这样fork后立马执行exec的成本就很是小了。而vfork由于共享内存因此比较危险。操作系统
为何会出现vfork?线程
缘由是: 起初只有fork,可是不少程序在fork一个子进程后就exec一个外部程序,因而fork须要copy父进程的数据这个动做就变得毫无心了,并且还很重,因此,搞出了个父子进程共享的vfork。因此,vfork本就是为了exec而生。指针
exit与return的区别:对象
exit函数在头文件stdlib.h中。
exit(0):正常运行程序并退出程序;
exit(1):非正常运行致使退出程序;
return():返回函数,若在main主函数中,则会退出函数并返回一值,能够写为return(0),或return 0。
详细说:
1. return返回函数值,是关键字;exit是一个函数。
2. return是语言级别的,它表示了调用堆栈的返回;而exit是系统调用级别的,它表示了一个进程的结束。
3. return是函数的退出(返回);exit是进程的退出。
4. return是C语言提供的,exit是操做系统提供的(或者函数库中给出的)。
5. return用于结束一个函数的执行,将函数的执行信息传出个其余调用函数使用;exit函数是退出应用程序,删除进程使用的内存空间,并将应用程序的一 个状态返回给OS,这个状态标识了应用程序的一些运行信息,这个信息和机器和操做系统有关,通常是 0 为正常退出,非0 为非正常退出。
6. 非主函数中调用return和exit效果很明显,可是在main函数中调用return和exit的现象就很模糊,多数状况下现象都是一致的。
为何return会挂掉,exit()不会?
从上面咱们知道,结束子进程的调用是exit()而不是return,若是你在vfork中return了,那么,这就意味main()函数return了,注意由于函数栈父子进程共享,因此整个程序的栈就出现问题了。若是你在子进程中return,那么基本是下面的过程:
(1)、首先子进程的main() 函数 return了。
(2)、而main()函数return后,一般会调用 exit()或类似的函数(如:exitgroup())。
(3)、这时,父进程收到子进程exit(),开始从vfork返回,可是父进程的栈都被子进程干废掉了,你让我怎么执行?(注:栈会返回一个诡异一个栈地址,对于某些内核版本的实现,直接报“栈错误”,然而,对于某些内核版本的实现,因而有可能会再次调用main(),因而进入了一个无限循环的结果,直到vfork 调用返回 error)
再回到 return 和 exit,return会释放局部变量,并弹栈,回到上级函数执行。exit直接退掉。若是你用c++ 你就知道,return会调用局部对象的析构函数,exit不会。(注:exit不是系统调用,是glibc对系统调用 _exit()或_exitgroup()的封装)。
可见,子进程调用exit() 没有修改函数栈,因此,父进程得以顺利执行。
内核代码分析:
linux建立子进程实际是一个复制父进程的过程。因此更贴切的说法是clone。linux一开始使用fork的缘由是当时clone这个词尚未流行。 实际存在fork,clone,vfork 三个系统调用。fork是彻底复制,clone则是有选择的复制,vfork则彻底使用父进程的资源。能够理解vfork是建立的线程。 vfork的出现主要是为了当即就执行exec的程序考虑的。可是后来的kernel都支持copy_on_write ,因此vfork提升效率的机制也没有那么明显了。
内核中三个系统调用最后都是调用do_fork:
fork:return do_fork(SIGCHLD, regs.esp, s, 0);
clone:return do_fork(clone_flags, newsp, s, 0);
vfork: return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.esp, s, 0);
#define CLONE_VFORK 0x00004000 /* set if the parent wants the child to wake it up on mm_release*/
#define CLONE_VM 0x00000100 /* set if VM shared between processes */
上面两个宏指出:vfork 要求子进程执行mm_release 后唤醒 父进程, 而且共享虚拟内存
为何要求子进程先行呢?
拿虚拟内存作比方。 进程须要有结构管理本身的虚拟内存空间, 该结构在进程 结构体 task_struct 中就是一个mm_struct 类型的指针。fork的时候内核会新建结构体,将该mm_struct 自己以及下级结构都复制一份,并设置子进程的mm_struct 指向新的内存。而vfork则只是复制了task_struct 自己,并无递归下去。简单说就是:fork复制了内存,vfork复制了指针。
相关例子:
fork
vfork
运行结果为:
fork运行结果:
vfork运行结果:
一、return返回时出错:
二、exit返回结果:
运行结果说明:vfrok时父、子进程共享数据段,fork时是进行拷贝。若是,vfork子进程中,使用return返回时,出现段错误。