当您调用时vfork()
,将创建一个新进程,并且该新进程借用父进程的进程映像(堆栈除外)。子进程被赋予了自己的新堆栈星,但是不允许return
从调用的函数vfork()
。
子进程运行时,父进程被阻塞,因为子进程借用了父进程的地址空间。
无论您做什么,仅访问堆栈的所有内容都只会修改孩子的私有堆栈。但是,如果您修改全局数据,则这将修改公共数据,从而也影响父级。
修改全局数据的事物包括:
调用malloc()或free()
使用stdio
修改信号设置
修改不是在调用函数本地的变量vfork()
。
...
一旦调用_exit()
(重要,从不调用exit()
),子级将终止,并将控制权交还给父级。
如果您从exec*()
系列中调用任何函数,则会使用新的程序代码,新的数据以及来自父级的堆栈的一部分来创建新的地址空间(请参见下文)。一旦准备就绪,子代便不再从子代借用地址空间,而是使用自己的地址空间。
该控件被交还给父级,因为它的地址空间不再被另一个进程使用。
重要说明:在Linux上,没有实际的vfork()
实现。Linux而是vfork()
基于fork()
SunOS-4.0在1988年提出的“ 写时复制” 概念实现的。为了使用户相信他们使用vfork()
,Linux只是设置共享数据并挂起父级,而子级没有调用_exit()
或其中一个exec*()
功能。
因此,Linux不能受益于Real vfork()
不需要为内核中的子代建立地址空间描述的事实。这导致的vfork()
速度不比快fork()
。在实现实数的系统上vfork()
,它的速度通常比fork()
使用vfork()
- ksh93
,最新的Bourne Shell
和csh
。
永远不要exit()
从vfork()
ed孩子exit()
那里打电话的原因是,如果从打电话之前开始就没有数据丢失,则刷新stdio vfork()
。这可能会导致奇怪的结果。
BTW:posix_spawn()
是在之上实现的vfork()
,因此vfork()
不会从OS中删除。已经提到Linux不vfork()
用于posix_spawn()
。
对于堆栈,几乎没有文档,这是Solaris手册页所说的内容:
The vfork() and vforkx() functions can normally be used the
same way as fork() and forkx(), respectively. The calling
procedure, however, should not return while running in the
child's context, since the eventual return from vfork() or
vforkx() in the parent would be to a stack frame that no
longer exists.
因此,实现可以做任何喜欢的事情。Solaris实现使用共享内存作为函数调用的堆栈帧vfork()
。没有实现可从父级授予对堆栈较旧部分的访问权限。