为什么fork和exec保持2个单独的调用

时间:2011-02-23 12:12:19

标签: unix process kernel fork

我理解fork,vfork,exec,execv,execp之间的区别。所以请不要咆哮。 我的问题是关于unix进程创建的设计。为什么设计师会想到创建两个单独的调用(fork和exec)而不是保持一个紧密的调用(spawn)。 良好的API设计是一个原因,以便开发人员能够更好地控制流程创建吗? 是因为性能原因,我们可以延迟为子进程分配进程表和其他内核结构,直到写入时复制或访问时复制?

5 个答案:

答案 0 :(得分:7)

主要原因可能是fork()exec()步骤的分离允许使用其他系统调用来完成子环境的任意设置。例如,您可以:

  • 设置一组任意打开的文件描述符;
  • 改变信号掩码;
  • 设置当前工作目录;
  • 设置流程组和/或会话;
  • 设置用户,组和补充组;
  • 设置硬资源和软资源限制;

......还有更多。如果您要将这些调用合并到一个spawn()调用中,则必须具有非常复杂的接口,以便能够对子环境中所有这些可能的更改进行编码 - 以及是否添加了新设置,界面需要改变。另一方面,单独的fork()exec()步骤允许您使用普通系统调用(open()close()dup()fcntl() ,...)在exec()之前操纵孩子的环境。

可以轻松支持新功能(例如capset()

答案 1 :(得分:4)

fork和exec做了完全不同的事情。

  • fork() - 重复进程
  • exec() - 替换进程

有很多理由不使用另一个。您可以代表您的控制父应用程序分叉执行任务的子进程,例如,在unix世界中非常常见。你可以,例如为其他一些古怪的应用程序设置前置条件,然后从你的启动器应用程序执行它而不使用fork。

答案 2 :(得分:0)

AFAIK,最初只有fork()。但性能原因要求创建exec(),它不会重新创建将被立即覆盖的内核结构。< - 这是错误的。

当进程需要创建一个不是自身副本的子进程时,会出现性能问题。 fork()复制与进程相关的内核数据,这些数据将立即被exec()替换。因此引入了vfork(),它不会复制过多的内核数据和任何过程数据;在它之后,一个进程应该调用exec()之类的东西,并且父进程被暂停,直到子进程为止。但是,请参阅“错误”部分以了解vfork()问题的描述。

答案 3 :(得分:0)

摘自本书草案xv6 a simple, Unix-like teaching operating system用于MIT课程6.828:

  

现在应该清楚为什么将fork和exec分开调用是一个好主意。因为如果它们是分开的,则外壳程序可以派生一个孩子,在孩子中使用open,close,dup来更改标准输入和输出文件描述符,然后执行。无需更改正在执行的程序(在我们的示例中为cat)。如果将fork和exec组合到单个系统调用中,则外壳将需要一些其他(可能更复杂)的方案来重定向标准输入和输出,否则程序本身将必须了解如何重定向I / O。

基本上如caf所述,但提供了很好的参考。实现一个简单的外壳可能会使原因很清楚。

答案 4 :(得分:-2)

fork()只能用于创建子进程。只能完成父进程的复制。 而exec()可用于启动系统上的任何新进程。 我认为两者之间没有相关性。