c - referendum - fork()如何知道何時返回0?




brexit referendum result (4)

採用以下示例:

int main(void)
{
     pid_t  pid;

     pid = fork();
     if (pid == 0) 
          ChildProcess();
     else 
          ParentProcess();
}

所以糾正我,如果我錯了,一旦fork()執行子進程被創建。 現在通過這個answer fork()返回兩次。 這對於父進程來說是一次,對於子進程則是一次。

這意味著在fork調用期間存在兩個單獨的進程,而不是在結束之後。

現在我不明白它如何理解如何為子進程返回0以及為父進程返回正確的PID。

這讓它變得非常混亂。 這個answer表明fork()通過複製進程的上下文信息並手動將返回值設置為0來工作。

首先,我說對任何函數的返回都放在一個寄存器中嗎? 因為在單個處理器環境中,進程只能調用一個只返回一個值的子例程(如果我錯了,請糾正我)。

假設我在例程中調用函數foo()並且該函數返回一個值,該值將存儲在一個寄存器中,如BAR。 每次函數想要返回一個值時,它將使用特定的處理器寄存器。 因此,如果我能夠手動更改過程塊中的返回值,我可以更改返回到函數的值嗎?

所以我認為fork()的工作原理是正確的嗎?


fork系統調用創建一個新進程並從父進程複製許多狀態。 文件描述符表被複製,內存映射及其內容等等。狀態在內核中。

內核跟踪每個進程的一個問題是這個進程需要在從系統調用,陷阱,中斷或上下文切換返回時恢復的寄存器值(大多數上下文切換發生在系統調用或中斷上)。 這些寄存器保存在系統調用/陷阱/中斷中,然後在返回用戶空間時恢復。 系統調用通過寫入該狀態返回值。 叉子的作用是什麼。 父fork獲取一個值,子進程獲取另一個值。

由於分叉進程與父進程不同,因此內核可以對其執行任何操作。 在寄存器中給它任何值,給它任何內存映射。 要實際確保除了返回值之外的幾乎所有內容都與父進程中的相同,這需要更多的努力。


在Linux中fork()發生在內核中; 實際的地方是_do_fork 。 簡化後, fork()系統調用可能就像

pid_t sys_fork() {
    pid_t child = create_child_copy();
    wait_for_child_to_start();
    return child;
}

所以在內核中, fork()實際上返回一次 ,進入父進程。 但是,內核還會將子進程創建為父進程的副本; 但它不是從普通函數返回,而是合成地為子進程的新創建的線程創建新的內核堆棧 ; 然後上下文切換到該線程(和進程); 當新創建的進程從上下文切換函數返回時,它將使子進程的線程最終返回到用戶模式,其中0作為fork()的返回值。

用戶區中的fork()基本上只是一個瘦包裝器,它返回內核放入其堆棧/返回寄存器的值。 內核設置新的子進程,以便它通過這個機制從其唯一的線程返回0; 並且子系統pid在父系統調用中返回,因為來自任何系統調用的任何其他返回值read(2)read(2)將是。


對於每個正在運行的進程,內核都有一個寄存器表,用於在進行上下文切換時加載。 fork()是一個系統調用; 一個特殊的調用,當進行時,進程獲得上下文切換,執行調用的內核代碼在不同的(內核)線程中運行。

系統調用返回的值放在應用程序在調用後讀取的特殊寄存器(x86中的EAX)中。 當調用fork() ,內核會生成進程的副本,並且在每個進程描述符的每個寄存器表中寫入適當的值:0和pid。


您首先需要了解多任務處理的工作原理。 理解所有細節是沒有用的,但是每個進程都在由內核控制的某種虛擬機中運行:一個進程有自己的內存,處理器和寄存器等。這些虛擬對象映射到真實的虛擬機上(神奇的是在內核中),並且有一些機器隨著時間的推移將虛擬上下文(進程)交換到物理機器。

然後,當內核分叉進程( fork()是內核的一個條目),並在進程中創建幾乎所有內容的副本到進程時,它就能夠修改所需的一切。 其中之一是修改相應的結構,為子節點返回0,父節點的pid從當前調用fork返回。

注意:nether說“fork返回兩次”,函數調用只返回一次。

想想一個克隆機器:你單獨進入,但兩個人退出,一個是你,另一個是你的克隆(非常不同); 克隆機器時,可以為克隆設置與您不同的名稱。







internals