fork()、vfork()、exec()和clone()的区别

新手上路,请多包涵

我希望在 Google 上找到这四个之间的区别,并且我预计会有大量关于此的信息,但是这四个调用之间确实没有任何可靠的比较。

我开始尝试编译一种基本的概览,看看这些系统调用之间的差异,这就是我得到的。所有这些信息是否正确/我是否遗漏了任何重要的信息?

Fork :fork 调用基本上复制了当前进程,几乎在所有方面都相同(并非所有内容都被复制,例如,某些实现中的资源限制,但想法是创建为关闭副本尽可能)。

新进程(子)获得不同的进程 ID(PID),并将旧进程(父)的 PID 作为其父 PID(PPID)。因为这两个进程现在运行的代码完全相同,所以它们可以通过 fork 的返回码来判断哪个是哪个 - 子进程得到 0,父进程得到子进程的 PID。当然,这就是全部,假设 fork 调用有效 - 如果没有,则不会创建子节点并且父节点会收到错误代码。

Vfork : The basic difference between vfork() and fork() is that when a new process is created with vfork() , the parent process is temporarily suspended ,子进程可能会借用父进程的地址空间。这种奇怪的情况一直持续到子进程退出或调用 execve() ,此时父进程继续。

这意味着一个 vfork() 的子进程必须小心避免意外修改父进程的变量。特别是子进程不能从包含 vfork() 调用的函数返回,也不能调用 exit() (如果需要退出,应该使用 _exit() ; 实际上,对于正常的孩子也是如此 fork() )。

Exec : exec 调用是一种基本上用新程序替换整个当前进程的方法。它将程序加载到当前进程空间并从入口点运行它。 exec() 用函数指向的可执行文件替换当前进程。除非出现 exec() 错误,否则控制永远不会返回到原始程序。

Clone : clone() 作为 fork() 创建一个新进程。与 fork() 不同,这些调用允许子进程与调用进程共享其部分执行上下文,例如内存空间、文件描述符表和信号处理程序表。

当使用 clone() 创建子进程时,它执行函数应用程序 fn(arg) (这与 fork() 不同,其中从原始点继续在子进程中执行 fork() 调用。) fn 参数是一个指向函数的指针,子进程在其执行开始时调用该函数。 arg 参数被传递给 fn 函数。

fn(arg) 函数应用程序返回时,子进程终止。 fn 返回的整数是子进程的退出代码。子进程也可以通过调用 exit(2) 或在收到致命信号后显式终止。

得到的信息:

感谢您抽时间阅读 ! :)

原文由 user476033 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.1k
2 个回答
  • vfork() 是一个过时的优化。在良好的内存管理之前, fork() 制作了父内存的完整副本,因此非常昂贵。因为在许多情况下 fork() 后面跟着 exec() ,它会丢弃当前的内存映射并创建一个新的映射,这是不必要的开销。如今, fork() 不复制内存; it’s simply set as “copy on write”, so fork() + exec() is just as efficient as vfork() + exec() .

  • clone()fork() 使用的系统调用。使用一些参数,它创建一个新进程,使用其他参数,它创建一个线程。它们之间的区别只是哪些数据结构(内存空间、处理器状态、堆栈、PID、打开的文件等)是共享的或不共享的。

原文由 Javier 发布,翻译遵循 CC BY-SA 2.5 许可协议

  • execve() 将当前可执行映像替换为从可执行文件加载的另一个映像。
  • fork() 创建一个子进程。
  • vfork() is a historical optimized version of fork() , meant to be used when execve() is called directly after fork() .事实证明,它在非 MMU 系统中运行良好(其中 fork() 不能以有效的方式工作)以及当 fork() 具有巨大内存占用的进程运行一些小程序时(想想Java的 Runtime.exec() )。 POSIX 已经标准化了 posix_spawn() 以取代后两种更现代的使用 vfork()
  • posix_spawn() 相当于 fork()/execve() ,并且还允许在两者之间进行一些 fd 杂耍。它应该取代 fork()/execve() ,主要用于非 MMU 平台。
  • pthread_create() 创建一个新线程。
  • clone() 是一个特定于 Linux 的调用,可用于实现从 fork()pthread_create() 的任何内容。它提供了很多控制权。灵感来自 rfork()
  • rfork() 是 Plan-9 特定的调用。它应该是一个通用调用,允许在完整进程和线程之间进行多种程度的共享。

原文由 ninjalj 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题