歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

談談守護進程與僵屍進程

維護的第一個商業服務就用了兩次fork產生守護進程的做法,前兩天在網上看到許多帖子以及一些unix書籍,認為一次fork後產生守護進程足夠了,各有道理吧,不過多了一次fork到底是出於什麼目的呢?


進程也就是task,看看內核裡維護進程的數據結構task_struct,這裡有兩個成員:

[cpp]
  1. struct task_struct {  
  2.     volatile long state;  
  3.     int exit_state;  
  4.     ...  
  5. }  
看看include/linux/sched.h裡的value取值:

[cpp]
  1. #define TASK_RUNNING        0   
  2. #define TASK_INTERRUPTIBLE  1   
  3. #define TASK_UNINTERRUPTIBLE    2   
  4. #define __TASK_STOPPED      4   
  5. #define __TASK_TRACED       8   
  6. /* in tsk->exit_state */  
  7. #define EXIT_ZOMBIE     16   
  8. #define EXIT_DEAD       32   
  9. /* in tsk->state again */  
  10. #define TASK_DEAD       64   
  11. #define TASK_WAKEKILL       128   
  12. #define TASK_WAKING     256   
  13. #define TASK_STATE_MAX      512  
可以看到,進程狀態裡除了大家都理解的running/interuptible/uninterruptible/stop等狀態外,還有一個ZOMBIE狀態,這個狀態是怎麼回事呢?


這是因為linux裡的進程都屬於一顆樹,樹的根結點是linux系統初始化結束階段時啟動的init進程,這個進程的pid是1,所有的其他進程都是它的子孫。除了init,任何進程一定有他的父進程,而父進程會負責分配(fork)、回收(wait4)它申請的進程資源。這個樹狀關系也比較健壯,當某個進程還在運行時,它的父進程卻退出了,這個進程卻沒有成為孤兒進程,因為linux有一個機制,init進程會接管它,成為它的父進程。這也是守護進程的由來了,因為守護進程的其中一個要求就是希望init成為守護進程的父進程。


如果某個進程自身終止了,在調用exit清理完相關的內容文件等資源後,它就會進入ZOMBIE狀態,它的父進程會調用wait4來回收這個task_struct,但是,如果父進程一直沒有調用wait4去釋放子進程的task_struct,問題就來了,這個task_struct誰來回收呢?永遠沒有人,除非父進程終止後,被init進程接管這個ZOMBIE進程,然後調用wait4來回收進程描述符。如果父進程一直在運行著,這個ZOMBIE會永遠的占用系統資源,用KILL發任何信號量也不能釋放它。這是很可怕的,因為服務器上可能會出現無數ZOMBIE進程導致機器掛掉。

Copyright © Linux教程網 All Rights Reserved