簡體   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