vfork() - Unix,Linux 系统调用
Tutorials Point


  Unix 初学者指南
  Unix Shell 编程
  高级 Unix
  Unix 有用参考
  Unix 有用资源
  精选阅读

版权所有 © 2014 tutorialspoint



  首页     参考     讨论论坛     关于 TP  

vfork() - Unix,Linux 系统调用


previous next AddThis Social Bookmark Button

广告

名称

vfork - 创建子进程并阻塞父进程

语法

#include <sys/types.h>
#include <unistd.h> 

pid_t vfork(void);

标准描述

(来自 SUSv2/POSIX 草案。)vfork() 函数与 fork() 的效果相同,除了 vfork() 创建的进程如果修改了除用于存储 vfork() 返回值的 pid_t 类型变量之外的任何数据,或者从调用 vfork() 的函数中返回,或者在成功调用 _exit() 或 exec() 系列函数之一之前调用任何其他函数,则其行为未定义。

Linux 描述

vfork() 就像 fork(2) 一样,创建调用进程的子进程。有关详细信息以及返回值和错误,请参阅 fork(2)。

vfork() 是 clone(2) 的特例。它用于创建新进程,而无需复制父进程的页表。在性能敏感的应用程序中,它可能很有用,在这些应用程序中,将创建一个子进程,然后立即发出 execve()

vfork() 与 fork() 的区别在于,父进程会暂停,直到子进程调用 execve(2) 或 _exit(2)。子进程与父进程共享所有内存,包括堆栈,直到子进程发出 execve()。子进程不得从当前函数返回或调用 exit(),但可以调用 _exit()。

信号处理程序是继承的,但不是共享的。父进程的信号在子进程释放父进程的内存后到达。

历史描述

在 Linux 下,fork() 是使用写时复制页面实现的,因此 fork() 产生的唯一开销是复制父进程页表所需的时间和内存,以及为子进程创建唯一的任务结构。但是,在过去,fork() 需要完全复制调用者的数据空间,这通常是不必要的,因为通常随后会立即执行 exec()。因此,为了提高效率,BSD 引入了 vfork() 系统调用,它没有完全复制父进程的地址空间,而是借用了父进程的内存和控制线程,直到调用 execve() 或退出发生。在子进程使用其资源时,父进程会被挂起。vfork() 的使用很棘手:例如,不修改父进程中的数据取决于知道哪些变量存储在寄存器中。

错误

Linux 从过去重现这种幽灵,这相当不幸。BSD 手册页指出:“当实现适当的系统共享机制时,此系统调用将被消除。用户不应依赖 vfork() 的内存共享语义,在这种情况下,它将与 fork() 同义。”

从形式上讲,上面给出的标准描述不允许使用 vfork(),因为后续的 exec() 可能会失败,然后会发生什么是不确定的。

信号处理的细节比较模糊,并且在不同的系统之间有所不同。BSD 手册页指出:“为了避免可能的死锁情况,处于 vfork() 中间的子进程永远不会收到 SIGTTOU 或 SIGTTIN 信号;相反,允许输出或 ioctl,输入尝试会导致文件结束指示。”

目前(Linux 2.3.25),strace(1) 无法跟踪 vfork(),需要内核补丁。

历史

vfork() 系统调用出现在 3.0BSD 中。在 4.4BSD 中,它与 fork() 同义,但 NetBSD 再次引入了它,参见 http://www.netbsd.org/Documentation/kernel/vfork.html。在 Linux 中,它一直等价于 fork(),直到大约 2.2.0-pre6。从 2.2.0-pre9(在 i386 上,在其他架构上稍晚一些)开始,它是一个独立的系统调用。支持已添加到 glibc 2.0.112 中。

符合标准

4.3BSD、POSIX.1-2001。标准对 vfork() 提出的要求弱于对 fork() 提出的要求,因此,其中两者同义的实现符合标准。特别是,程序员不能依赖父进程在调用 execve() 或 _exit() 之前保持阻塞,也不能依赖任何关于共享内存的特定行为。

另请参阅



previous next Printer Friendly

广告


  

广告



广告