根据 vfork()
手册页,如果 vfork()
在调用 _exit 或 exec 之前修改除 pid_t 之外的任何数据,则行为未定义系统调用系列。
由此我了解到,如果vfork()
创建的子进程调用exec()
,那么它可以修改任何数据,而且行为仍然不是未定义。
我的问题是:
众所周知,子进程共享父地址空间,那么如果子进程使用 exec 覆盖、 self 和父镜像,行为不是未定义的,怎么会这样呢?
如果子调用 exec 然后它返回,父会发生什么? parent 是否开始使用 child 使用 exec 创建的新副本?
最佳答案
exec
调用用一个全新的地址空间替换了 child 的整个地址空间。任何共享地址空间都将被调用完全替换。
vfork
函数仅作为优化存在。对于某些操作系统,fork
非常昂贵,因为子进程可能会修改映射到内存中的任何页面,因此必须修改每个页面以在写入时复制(或者,最初,实际复制!),以免修改父进程的相应页面页。一个非常常见的序列是 fork
紧接着是 exec
,迫使这些系统重新映射所有页面只是为了在一瞬间将它们全部丢弃。 vfork
允许您在假设您无论如何都不会使用它们的情况下,将映射保留在子进程中的未定义状态,而不是修改所有映射的麻烦。
因此,在 vfork
之后做某些事情可能会造成困惑。但是只要你调用 exec
,所有未定义的映射都会消失。
在实践中,操作系统处理 vfork
有两种方式之一:对于将所有映射更改为写入时复制成本低廉或尚未实现 vfork
优化的操作系统,vfork
与 fork
相同。对于确实使用 vfork
优化的操作系统,vfork
让父子完全共享大部分页面,如果子修改它们(它们在父中修改),就会导致不好的事情发生。
所以对你的问题的简短回答是,如果 vfork
是这样设计的,它就不能用于其唯一的预期目的。
关于c - 如果 vfork() 调用 exec 族,为什么它不是未定义的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7058244/