在Unix中调用fork()时会发生什么?

时间:2011-09-17 13:38:11

标签: c unix fork process

我试过看一下,但是在调用fork()之后,我正在努力理解父进程和子进程之间的关系。

它们是完全独立的进程,只与id / parent id相关联吗?或者他们共享记忆?例如,每个进程的“代码”部分是重复的,以便每个进程都有自己的相同副本,或者以某种方式“共享”以便只存在一个?

我希望这是有道理的。

以完全披露的名义,这是“与家庭作业相关”;虽然不是书中的直接问题,但我觉得它主要是学术性的,在实践中,我可能不需要知道。

4 个答案:

答案 0 :(得分:21)

在整个过程中,整个内存都是重复的。

实际上,它使用“写入时复制”系统。第一次进程在fork()之后更改其内存时,会对修改后的页面(通常为4kB)进行单独复制。

通常不修改进程的代码段,在这种情况下它仍然是共享的。

答案 1 :(得分:17)

逻辑上,fork创建原始进程的相同副本,该副本在很大程度上独立于原始进程。出于性能原因,内存与copy-on-write语义共享,这意味着未修改的内存(如代码)仍然是共享的。

文件描述符是重复的,因此分叉进程原则上可以代表父进程接管数据库连接(或者如果程序员有点扭曲,它们甚至可以与数据库联合通信)。更常见的是,这用于在进程之间设置管道,以便您可以编写find -name '*.c' | xargs grep fork

共享一堆其他东西。有关详细信息,请参阅here

一个重要的遗漏是线程 - 子进程只继承了调用fork()的线程。这导致多线程程序中没有问题,因为锁定在父级中的互斥锁等的状态是特定于实现的(并且不要忘记malloc()printf()在内部使用锁)。在fork()返回后,孩子唯一安全的做法是尽快调用execve(),即使这样,你也必须对文件描述符保持谨慎。有关完整的恐怖故事,请参阅here

答案 2 :(得分:5)

  1. 它们是单独的进程,即Child和Parent将具有单独的PID
  2. 孩子将继承父
  3. 中的所有开放描述符
  4. 内部页面,即可以与.text区域不同地修改的堆栈/堆区域,将与父项和子项共享,直到其中一个尝试修改内容。在这种情况下,将创建一个新页面,并将特定于正在修改的页面的数据复制到这个新分配的页面,并映射到与导致更改的页面相对应的区域 - 可以是父级或子级。这被称为COW(上述论坛中其他成员在回答中提到)。
  5. Child可以完成执行,直到父级使用wait()或waitpid()调用回收将处于ZOMBIE状态。这将有助于从进程表中清除子进程的进程,并允许重用子进程。通常当一个孩子死亡时,SIGCHLD信号被发送到父母,这将理想地导致在该处理程序中执行wait()调用之后调用处理程序。
  6. 如果Parent退出但没有清理已经运行或僵尸的子进程(通过wait()waitpid调用),则init()进程(PID 1)将成为这些孤立子进程的父进程。此init()进程定期执行wait()或waitpid()调用。
  7. 编辑:错别字 HTH

答案 3 :(得分:2)

是的,它们是独立的流程,但有一些特殊的“属性”。其中一个是孩子与父母的关系。

但更重要的是以写时复制(COW)方式共享内存页:直到其中一个执行页面上的写入(全局变量或其他),内存页面被共享。执行写入时,内核会创建该页面的副本并映射到正确的地址。

COW魔术是在内核中通过将页面标记为只读并使用故障机制来完成的。