fork()詳解

<一>: fork()函數用來創建新的進程,它的特點是調用一次返回兩次( 在原來的進程中返回新進程的 PID(新進程的 PID 肯定不等於 0), 在新進程中返回爲 0.)

函數原型:pid_t fork(void);

pid_t getpid(); 獲取當前進程的 pid 值。
pid_t getppid(); 獲取當前進程的父進程 pid 值。
 

fork

   圖一

如圖一所示 :我們將A 進程, 也就是調用 fork 的進程稱之爲父進程, 而新的進程(B 進程)稱之爲子進程。

<二>:fork 的特性: fork 調用生成的新進程與其父進程誰先執行不一定。

<三>:fork的執行過程:

       (1)申請PID

       (2)申請PCB結構

       (3)複製父進程的PCB

       (4)將子進程的運行狀態設置爲不可執行的

       (5)將子進程中的某些屬性清零,某些保留,某些修改

       (6)複製父進程的頁(用到了寫時拷貝技術)

這裏所用到的寫時拷貝技術指的是父子進程在初始階段共享所有的數據(全局、 棧區、 堆區、 代碼), 內核會將所有的區域設置爲只讀。 當父子進程中任意一個進程試圖修改其中的數據時, 內核纔會將要修改的數據所在的區域(頁) 拷貝一份。

寫時拷貝技術針對的是: fork 之後, 子進程往往會替換成新的程序, 所以在 fork 的時候就不需要將父進程完全拷貝出來, 當替換新程序時, 直接給子進程重新分配空間即可。
 

<四>:父子進程建數據共享問題:.data   .bss   .text   .heap的數據都不共享 ,但是父子進程之間共享 fork 之前打開的文件描述符, 並且父子進程共用文件讀寫偏移量。原理如圖二所示:

圖二   

                        圖二

所以, 在執行邏輯上, fork 之前打開的文件, 要 close 兩次!!


<五>在調用fork()執行後,可能會產生孤兒進程和殭屍進程,讓我們一起看看到底什麼是孤兒進程和殭屍進城以及怎麼解決他們。

孤兒進程: 父進程結束, 子進程依舊存在。 那麼子進程就被稱爲孤兒進程。 系統會將所有的孤兒進程掛載到 init 下。 init 進程的 pid = 1

殭屍進程: 1,進程結束, 但是 PCB 沒釋放,2,子進程結束, 父進程未結束, 並且父進程未獲取子進程的退出狀態

處理殭屍進程方法:
1、 結束其父進程。
2、 父進程獲取子進程的退出狀態: 在父進程中調用wait()函數,但是wait 函數會阻塞運行, 直到第一個子進程退出。

3、在子進程結束時,子進程給父進程發一個信號(告知父進程我已經結束了)父進程接收到信號後在對子進程做處理

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章