程序(process)是計算機中的程式關於某資料集合上的一次執行活動,是系統進行資源分配和排程的基本單位,是作業系統結構的基礎。程式是指令、資料及其組織形式的描述,程序是程式的實體。程序是乙個具有獨立功能的程式關於某個資料集合的一次執行活動。程序可以申請和擁有系統資源,是乙個動態的概念,是乙個活動的實體。程序不只是程式的**,還包括當前的活動,通過程式計數器的值和處理暫存器的內容來表示。通俗點講,程序是一段程式的執行過程,是個動態概念。
程式執行必須載入在記憶體中,當有過多的就緒態或阻塞態程序在記憶體中沒有執行,因為記憶體很小,有可能不足。系統需要把他們移動到記憶體外磁碟中,稱為掛起狀態。就緒狀態的程序掛起就是掛起就緒狀態,阻塞程序掛起就稱為阻塞掛起狀態。
每個程序的產生都有自己的唯一的 id 號(pid),並且附帶有乙個它父程序的 id 號(ppid)。程序死亡時,id 被**。
程序間靠優先順序獲得 cpu 資源,時間片段輪換來更新優先順序,以保證不會乙個程序佔據 cpu 時間過長。每個程序都得到輪換執行,因為這個時間非常短,所以給我們就好像是系統在同時執行好多程序。
程序狀態
乙個父程序退出,而它的乙個或多個子程序還在執行,那麼那些子程序將成為孤兒程序。孤兒程序將被 init 程序(程序號為 1)所收養,並由 init 程序對它們完成狀態收集工作。
子程序死亡需要父程序來處理,那麼意味著正常的程序應該是子程序先於父程序死亡。當父程序先於子程序死亡時,子程序死亡時沒父程序處理,這個死亡的子程序就是孤兒程序。但孤兒程序與殭屍程序不同的是,由於父程序已經死亡,系統會幫助父程序**處理孤兒程序。所以孤兒程序實際上是不占用資源的,因為它終究是被系統**了。不會像殭屍程序那樣占用 id,損害執行系統。
子程序先於父程序退出後,子程序的 pcb 需要其父程序釋放,但是父程序並沒有釋放子程序的 pcb,這樣的子程序就稱為殭屍程序,殭屍程序實際上是乙個已經死掉的程序。
乙個程序在呼叫 exit 命令結束自己的生命的時候,其實它並沒有真正的被銷毀,而是留下乙個稱為殭屍程序(zombie)的資料結構(系統呼叫 exit,它的作用是使程序退出,但也僅僅限於將乙個正常的程序變成乙個殭屍程序,並不能將其完全銷毀)。在 linux 程序的狀態中,殭屍程序是非常特殊的一種,它已經放棄了幾乎所有記憶體空間,沒有任何可執行**,也不能被排程,僅僅在程序列表中保留乙個位置,記載該程序的退出狀態等資訊供其他程序收集,除此之外,殭屍程序不再占有任何記憶體空間。這個殭屍程序需要它的父程序來為它收屍,如果他的父程序沒有處理這個殭屍程序的措施,那麼它就一直保持殭屍狀態,如果這時父程序結束了,那麼 init 程序自動會接手這個子程序,為它收屍,它還是能被清除的。但是如果如果父程序是乙個迴圈,不會結束,那麼子程序就會一直保持殭屍狀態,這就是為什麼系統中有時會有很多的殭屍程序。
如果有大量的殭屍程序駐在系統之中,必然消耗大量的系統資源。但是系統資源是有限的,因此當殭屍程序達到一定數目時,系統因缺乏資源而導致奔潰。所以在實際程式設計中,避免和防範殭屍程序的產生顯得尤為重要。
用 ps 命令可以看到殭屍程序後有乙個,defunct 是已死的,殭屍的意思,可以看出這時的子程序已經是乙個殭屍程序了。也可以用命令 ps -aux | grep pid 檢視該程序狀態。
處理方式
如果父程序能及時處理,可能用 ps 命令就來不及看到子程序的殭屍狀態,但這並不等於子程序不經過殭屍狀態。如果父程序在子程序結束之前退出,則子程序將由 init 接管。init 將會以父程序的身份對殭屍狀態的子程序進行處理。所以殭屍程序會占用資源危害系統。我們應當避免殭屍程序的出現。
解決方式如下:
一種比較暴力的做法是將其父程序殺死,那麼它的子程序,即殭屍程序會變成孤兒程序,由系統來**。但是這種做法在大多數情況下都是不可取的,如父程序是乙個伺服器程式,如果為了**其子程序的資源,而殺死伺服器程式,那麼將導致整個伺服器崩潰,得不償失。顯然這種**程序的方式是不可取的,但其也有一定的存在意義。
sigchld訊號處理——wait 函式是用來處理殭屍程序的,但是程序一旦呼叫了 wait,就立即阻塞自己,由 wait 自動分析是否當前程序的某個子程序已經退出,如果讓它找到了這樣乙個已經變成殭屍的子程序,wait 就會收集這個子程序的資訊,並把它徹底銷毀後返回;如果沒有找到這樣乙個子程序,wait 就會一直阻塞在這裡,直到有乙個出現為止。
wait 函式
#include /*定義引數 status 用來儲存被收集程序退出時的一些狀態,它是乙個指向 int 型別的指標。但如果我們對這個子程序是如何死掉的毫不在意,只想把這個殭屍程序消滅掉,(事實上絕大多數情況下,我們都會這樣想),我們就可以設定這個引數為 null,就象下面這樣:pid=wait(null);如果成功,wait 會返回被收集的子程序的程序 id,如果呼叫程序沒有子程序,呼叫就會失敗,此時 wait 返回 -1,同時 errno 被置為echild。提供型別pid_t的定義,實際就是int型
*/#include
pid_t wait(
int *status)
由於呼叫 wait 之後,就必須阻塞,直到有子程序結束,所以,這樣來說是非常不高效的,我們的父程序難道要一直等待你子程序完成,最後才能執行自己的**嗎?難道就不能我父程序執行自己的**,你子程序什麼時候完成我就什麼時候去處理你,不用一直等你?當然是有這種方式了。
實際上當子程序終止時,核心就會向它的父程序傳送乙個 sigchld 訊號,父程序可以選擇忽略該訊號,也可以提供乙個接收到訊號以後的處理函式。對於這種訊號的系統預設動作是忽略它。我們不希望有過多的殭屍程序產生,所以當父程序接收到 sigchld 訊號後就應該呼叫 wait 或 waitpid 函式對子程序進行善後處理,釋放子程序占用的資源。
參考:
孤兒程序 孤兒程序組 守護程序
1.孤兒程序的定義 定義1 該程序組的每個成員的父程序要麼是該組的成員,要麼在其它會話中。定義2 乙個程序不是孤兒程序組的條件是 該組有乙個程序,其父程序在屬於同一會話的另乙個組中。只要能夠滿足上面其中的任乙個定義,則此程序組就是孤兒程序組。可能讀起來比較拗口,看圖 1 中的例子可能會清楚點。圖 1...
孤兒程序 殭屍程序
殭屍程序和孤兒程序 殭屍程序 殭屍程序是乙個比較特殊的狀態,當程序退出並且父程序沒有讀取到子程序的退出碼,就會產生殭屍程序,殭屍程序會一直儲存在程序表中,並且一直等待父程序讀取退出狀態碼。所以,只要子程序退出,父程序還在執行,但是父程序沒有讀取到子程序的狀態,子程序就會進入殭屍狀態。建立乙個殭屍程序...
殭屍程序, 孤兒程序
一,定義 當程序退出並且父程序 使用wait 系統呼叫 沒有讀取到子程序退出的返回 時就會產生殭屍程序。殭屍程序會以終止狀態保持在程序表中,並且會一直在等待父程序讀取退出狀態 簡單來說就是,在父程序中有乙個子程序,該子程序完成父程序交給的任務,子程序完成後會給父程序乙個任務結果返回,但父程序一直沒有...