繁体   English   中英

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

[英]What Happens When I Call fork() in Unix?

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

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

我希望这是有道理的。

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

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

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

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

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

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

一堆其他的东西是共享的。 详情请见此处

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

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

编辑:错别字HTH

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM