【问题标题】:What Happens When I Call fork() in Unix?在 Unix 中调用 fork() 会发生什么?
【发布时间】:2011-11-19 06:55:29
【问题描述】:

我尝试查找此内容,但在调用 fork() 后,我正在努力理解父进程和子进程之间的关系。

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

我希望这是有道理的。

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

【问题讨论】:

  • 要考虑的一件事:如果您并行执行同一个程序两次(例如,您有两个 vim 会话),这两个进程将(可能)共享相同的代码段,无论它们是否有父子关系。

标签: c unix fork process


【解决方案1】:

在进程看来,整个内存都是重复的。

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

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

【讨论】:

  • +1 不错。您能否详细说明调用setsid() 时会发生什么?代码分段?
  • 我对setsid()不是很熟悉,但我认为它不会影响写时复制功能。
  • setsid 与内存无关。
【解决方案2】:

从逻辑上讲,分叉会创建与原始进程相同的副本,该副本在很大程度上独立于原始进程。出于性能原因,内存使用写时复制语义共享,这意味着未修改的内存(例如代码)保持共享。

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

还有很多其他的东西是共享的。详情请见here。

一个重要的遗漏是线程——子进程只继承了调用fork()的线程。这会给多线程程序带来无穷无尽的麻烦,因为在父进程中锁定的互斥锁等的状态是特定于实现的(不要忘记malloc() 和printf() 在内部使用锁)。在fork() 返回后,孩子唯一安全的事情是尽快调用execve(),即使那样你也必须小心文件描述符。有关完整的恐怖故事,请参阅 here。

【讨论】:

  • 请注意,省略线程不是 POSIX 中的设计缺陷,而是“复制”进程概念的基本限制。每个锁都有一个所有者,那么在复制之后,谁应该拥有它?这对于进程本地互斥体可能无关紧要(父进程和子进程都可能最终得到一个副本,每个副本都由相应的线程拥有)但是进程共享互斥体呢?同样的问题也适用于 pre-pthreads 同步对象(文件锁等)和fork。基本上,forking 在不知道你的整个程序做了什么的情况下的想法是无法修复的。
【解决方案3】:
  1. 它们是独立的进程,即子进程和父进程将具有不同的 PID
  2. 子级将从父级继承所有打开的描述符
  3. 在内部,与 .text 区域不同,可以修改的页面(即堆栈/堆区域)将在父项和子项之间共享,直到其中一个尝试修改内容。在这种情况下,将创建一个新页面,并将特定于被修改页面的数据复制到这个新分配的页面,并映射到与导致更改的页面相对应的区域 - 可以是父或子。这称为 COW(上面论坛中的其他成员在他们的回答中提到过)。
  4. 子进程可以完成执行,直到父进程使用 wait() 或 waitpid() 调用将其回收,才会处于 ZOMBIE 状态。这将有助于从进程表中清除子进程条目,并允许重用子 pid。通常当一个子进程死亡时,SIGCHLD 信号会发送给父进程,理想情况下会导致调用一个处理程序,然后在该处理程序中执行 wait() 调用。
  5. 如果父进程在没有清理已经运行或僵尸子进程的情况下退出(通过 wait() waitpid 调用),init() 进程 (PID 1) 将成为这些现在孤儿进程的父进程。此 init() 进程定期执行 wait() 或 waitpid() 调用。

编辑:错别字 高温

【讨论】:

    【解决方案4】:

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

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

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

    【讨论】:

      猜你喜欢
      • 2014-03-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-03
      • 2012-02-10
      • 2020-11-22
      • 1970-01-01
      • 2015-01-03
      相关资源
      最近更新 更多