我试过看一下,但是在调用fork()之后,我正在努力理解父进程和子进程之间的关系。
它们是完全独立的进程,只与id / parent id相关联吗?或者他们共享记忆?例如,每个进程的“代码”部分是重复的,以便每个进程都有自己的相同副本,或者以某种方式“共享”以便只存在一个?
我希望这是有道理的。
以完全披露的名义,这是“与家庭作业相关”;虽然不是书中的直接问题,但我觉得它主要是学术性的,在实践中,我可能不需要知道。
答案 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)
答案 3 :(得分:2)
是的,它们是独立的流程,但有一些特殊的“属性”。其中一个是孩子与父母的关系。
但更重要的是以写时复制(COW)方式共享内存页:直到其中一个执行页面上的写入(全局变量或其他),内存页面被共享。执行写入时,内核会创建该页面的副本并映射到正确的地址。
COW魔术是在内核中通过将页面标记为只读并使用故障机制来完成的。