为什么默认的进程创建机制是fork?

为什么默认的进程创建机制是fork?

用于进程创建的 UNIX 系统调用 fork() 通过复制父进程来创建子进程。我的理解是,这几乎总是随后调用 exec() 来替换子进程的内存空间(包括文本段)。在 fork() 中复制父级的内存空间对我来说总是很浪费(尽管我意识到可以通过使内存段进行写时复制(因此只复制指针)来最大程度地减少浪费)。无论如何,有谁知道为什么流程创建需要这种重复方法?

答案1

是为了简化界面。fork和的替代品exec将类似于 Windows'创建进程功能。请注意有多少参数CreateProcess,其中许多是具有更多参数的结构。这是因为一切您可能希望控制新进程必须传递给CreateProcess.事实上,CreateProcess没有足够的参数,所以微软不得不添加创建进程为用户使用登录创建进程

使用该fork/exec模型,您不需要所有这些参数。相反,进程的某些属性被保留在exec.这允许您fork,然后更改您想要的任何流程属性(使用您通常使用的相同功能),并且然后 exec。在Linux中,fork没有参数,execve只有3个:要运行的程序、给它的命令行以及它的环境。 (还有其他exec函数,但它们只是execveC 库提供的包装器,用于简化常见用例。)

如果您想使用不同的当前目录启动进程: fork, chdir, exec.

如果您想重定向 stdin/stdout: fork、关闭/打开文件、exec.

如果要切换用户:fork, setuid, exec

所有这些东西都可以根据需要进行组合。如果有人提出了一种新的流程属性,您不必更改forkexec

正如 larsks 提到的,大多数现代 Unix 使用写时复制,因此fork不会涉及大量开销。

答案2

除了 cjm 的答案之外,单一 Unix 规范还定义了一个名为 的函数vfork()。该函数的工作方式与 fork 类似,不同之处在于,如果分叉进程除了尝试调用 exec 系列函数或调用_exit().

因此,定义行为的唯一用途是:

pid_t ret = vfork();
if(ret == 0)
{
    exec(...);
    _exit(EXIT_FAILURE); //in case exec failed for any reason.
}

那么它有什么vfork作用呢?它是一种廉价的fork。在没有写时复制的实现中,生成的进程将与原始进程共享内存空间(因此出现未定义的行为)。在写时复制的实现中,vfork允许与 相同fork(),因为写时复制实现速度很快。

还有一个可选posix_spawn函数(和一个posix_spawnp函数)可以直接创建一个新进程。 (也可以使用fork和通过库调用来实现它们exec,并且提供了示例实现。)

相关内容