当子进程在创建后立即调用 exec() 或 exit() 时,为什么要使用 vfork()?

Tim*_*Tim 11 linux process exit exec vfork

操作系统概念和 APUE 说

使用vfork(),父进程被挂起,子进程使用父进程的地址空间。因为 vfork() 不使用写时复制,如果子进程更改了父地址空间的任何页面,一旦恢复,父进程将可以看到更改的页面。因此,必须谨慎使用 vfork(),以确保子进程不会修改父进程的地址空间。

vfork() 旨在在子进程创建后立即调用 exec() 或 exit() 时使用。

我该如何理解最后一句话?

vfork()调用创建的子进程时exec(),不会exec()通过加载新程序来修改父进程的地址空间?

当一个子进程的创建vfork()调用exit(),并 exit()终止儿童在不修改父进程的地址空间?

我更喜欢Linux。

谢谢。

Ste*_*itt 15

vfork()调用创建的子进程时exec(),不会exec()通过加载新程序来修改父进程的地址空间?

不,exec()为新程序提供新的地址空间;它不会修改父地址空间。例如exec参见POSIX 中函数的讨论Linuxexecve()联机帮助页

当vfork()创建的子进程调用exit()时,exit()在终止子进程时是否不修改父进程的地址空间?

简单的exit()可能——它运行由正在运行的程序(包括它的库)安装的退出钩子。vfork()更具限制性;因此,在Linux上,它要求的使用_exit()调用C库的清理功能。

vfork()结果证明很难做到正确;它已在当前版本的 POSIX 标准中删除,posix_spawn()应改为使用。

但是,除非你真的知道你在做什么,你应该没有任何使用vfork()posix_spawn(); 坚持好老fork()exec()

上面链接的 Linux 联机帮助页提供了更多上下文:

然而,在过去的坏日子里, afork(2) 需要制作调用者数据空间的完整副本,这通常是不必要的,因为通常exec(3)在完成之后立即完成。因此,为了提高效率,BSD 引入了vfork() 系统调用,它没有完全复制父进程的地址空间,而是借用父进程的内存和控制线程,直到发生调用execve(2)或退出。当子进程使用其资源时,父进程被挂起。的使用 vfork()很棘手:例如,不修改父进程中的数据取决于知道哪些变量保存在寄存器中。

  • 有趣的是 vfork() 现在几乎战胜了其他一切。当你有 1 GB 的可写内存时,它比 fork() 快得多。 (2认同)
  • 请不要告诉人们使用`posix_spawn`。使用`posix_spawn`编写正确的代码比使用普通的旧`fork`要困难得多,如果你尝试,你可能会遇到没有文件操作或属性来完成你需要在两者之间完成的事情的砖墙`fork` 和 `exec`。并且它不能保证具有类似 vfork 的效率,因此它甚至不能解决人们希望它解决的问题。 (2认同)