2013-04-04 83 views
3

在* nix系統中,通過使用fork()系統調用來創建進程。例如,考慮init進程創建另一個進程。首先它自行分叉並創建一個具有init之類上下文的進程。只有在調用exec()時,這個子進程纔是一個新進程。那麼爲什麼需要中間步驟(創建一個與父母具有相同上下文的子女)?這不是浪費時間和資源,因爲我們正在創建一個上下文(消耗時間和浪費內存),然後寫它?在exec()之前有什麼用fork()?

這是爲什麼沒有實現分配一個空的內存區域,然後調用exec()?這會節省時間和資源嗎?

回答

3

的中間步驟,可以在子進程中設置共享資源,而不需要外部程序知道它。典型的例子是構建管:

// read output of "ls" 
// (error checking omitted for brevity) 
int pipe_fd[2]; 
pipe(&pipe_fd); 
if (fork() == 0) {  // child: 
    close(pipe_fd[0]); // we don't want to read from the pipe 
    dup2(pipe_fd[1], 1); // redirect stdout to the write end of the pipe 
    execlp("ls", "ls", (char *) NULL); 
    _exit(127);   // in case exec fails 
} 
// parent: 
close(pipe_fd[1]); 
fp = fdopen(pipe_fd[0], "r"); 
while (!feof(fp)) { 
    char line[256]; 
    fgets(line, sizeof line, fp); 
    ... 
} 

如何注意標準輸出管道的重定向在孩子做了,forkexec之間。當然,對於這個簡單的情況,可能會有一個spawning API,只要給出正確的參數,就可以自動執行此操作。但fork()設計可以對子進程中的每個進程資源進行任意操作 - 可以關閉不需要的文件描述符,修改每個進程的限制,放棄特權,操作信號掩碼等等。如果沒有fork(),產卵過程的API最終會變得非常胖或者不是非常有用。事實上,產生相互競爭的操作系統的過程通常會介於兩者之間。

至於浪費內存,它是用copy on write技術避免的。 fork()不會爲子進程分配新內存,而是將子進程指向父進程的內存,並且只有在頁面被寫入的情況下,纔會指示製作頁的副本。這使得fork()不僅內存效率高,而且速度很快,因爲它只需要複製一個「目錄」。

0

我不知道究竟是怎麼INIT過程的工作在內核中分叉,但回答你的,爲什麼你需要調用叉問題方面然後EXEC很簡單,因爲一旦你EXEC沒有回頭路。

如果檢查出的文檔here,它本質上需要一個新的進程,以催生(在調用)父進程重新開始控制,要麼等待它完成或坐下如守護進程可能會。

2

這是一個古老的投訴。很多人都問爲什麼fork()第一?,他們通常會提出一個操作,既可以從頭創建一個新的進程,也可以在其中運行一個程序。這種操作被稱爲spawn().

而他們總是說,這會不會更快?

而實際上,除了Unix家族之外的其他系統都確實以的方式進行了「產卵」方式。只有UNIX是基於fork()exec().

但它很有趣,UNIX一直比其他全功能系統快得多。它一直處理更多的用戶和負載。

多年來,Unix的速度更快。叉()不再真的可以複製地址空間,它只是共享使用一個叫做copy-on-write.技術它(稱爲vfork()一個很老叉優化也仍然存在。)

Kool-Aid.

0

只有在調用exec()時,這個子進程結果是一個新的 進程。

不是。在分叉之後,你已經有了新的進程,甚至與父進程沒有太大的不同。有些情況下,沒有執行官需要跟隨分叉。

那麼,爲什麼(生成帶有相同 上下文父母的孩子)的中間步驟需要的?

其中一個原因是因爲它創造了整個事情的有效方式。克隆通常不如從頭開始複雜。

是不是時間和資源的浪費,因爲我們正在創造一個 上下文(消耗時間,浪費內存),然後在寫呢?

這不是浪費時間和資源,因爲大部分資源都是虛擬的,這是由於使用了複製寫入機制。此外,聲明創建的上下文被覆蓋是不正確的。考慮到事實上沒有任何實際寫在第一位,沒有什麼是重寫的。這就是COW的重點。 「只有」進程地址空間(代碼,堆和堆棧)被替換,而不會被覆蓋。許多進程上下文被部分或完全保留,包括環境,文件描述符,優先級,被忽略的信號,當前和根目錄,限制,各種掩碼,處理器綁定,特權以及其他與進程地址空間不同的其他內容。

+0

克隆可能不如從頭開始複製,但如果我們爲了運行不同的程序而分叉,我們必須在fork之後執行'exec'。這個「執行」將打擊克隆所有的努力,所以OP提出的問題是爲什麼我們首先想克隆呢? – user4815162342 2013-04-04 22:12:05

+0

@ user4815162342更仔細地閱讀我的回覆。唯一被一個exec(進程地址空間)替代的成本幾乎不需要克隆,因爲它是在寫入時拷貝的。內核端的進程上下文,這是真正重要的是用exec來保存。沒有努力吹。 – jlliagre 2013-04-04 22:26:26

+0

好點,我跳過你最後一段。我仍然懷疑「幾乎沒有努力」的部分。在同一個操作系統上比較分叉和無叉進程創建會很有趣。 – user4815162342 2013-04-05 06:14:59

相關問題