控制終端,登錄會話和進程組通常是從父進程繼承下來的。我們的目的就是要擺脫它們,使之不受它們的影響。方法是在第1點的基礎上,調用setsid()使進程成為會話組長:
setsid函數用於創建一個新的會話,並擔任該會話組的組長。調用setsid有下面的3個作用:
(1)讓進程擺脫原會話的控制
(2)讓進程擺脫原進程組的控制
(3)讓進程擺脫原控制終端的控制
也就是說由於創建守護進程的第一步調用了fork函數來創建子進程,再將父進程退出。由於在調用了fork函數時,子進程全盤拷貝了父進程的會話期、進程組、控制終端等,雖然父進程退出了,但會話期、進程組、控制終端等並沒有改變,因此,這還不是真正意義上的獨立開來,而setsid函數能夠使進程完全獨立出來,從而擺脫其他進程的控制。
說明:當進程是會話組長時setsid()調用失敗。但第一點已經保證進程不是會話組長。setsid()調用成功後,進程成為新的會話組長和新的進程組長,並與原來的登錄會話和進程組脫離。由於會話過程對控制終端的獨占性,進程同時與控制終端脫離。 3. 禁止進程重新打開控制終端exit(0);//結束第一子進程,第二子進程繼續(第二子進程不再是會話組長)
注意:很多讀者就會問,為什麼要創建兩次進程呢? 這是因為第二步結束後,進程創建了一個新的會話組,並成為會話組長,而會話組長可能獲得控制終端,如果獲得了控制終端那麼或這個進程就不是守護進程了。所以添加了這幾句代碼,讓進程失去會話組長的身份,從而沒有獲得控制終端的權限。
4. 關閉打開的文件描述符這樣,內核在子進程結束時不會產生僵屍進程。這一點與BSD4不同,BSD4下必須顯式等待子進程結束才能釋放僵屍進程。
因為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進程導致機器掛掉。
8.守護進程退出處理#include < unistd.h > #include < signal.h > #include < sys/param.h > #include < sys/types.h > #include < sys/stat.h > void init_daemon(void) { int pid; int i; if(pid=fork()) exit(0);//是父進程,結束父進程 else if(pid< 0) exit(1);//fork失敗,退出 //是第一子進程,後台繼續執行 setsid();//第一子進程成為新的會話組長和進程組長 //並與控制終端分離 if(pid=fork()) exit(0);//是第一子進程,結束第一子進程 else if(pid< 0) exit(1);//fork失敗,退出 //是第二子進程,繼續 //第二子進程不再是會話組長 for(i=0;i< NOFILE;++i)//關閉打開的文件描述符 close(i); chdir("/tmp");//改變工作目錄到/tmp umask(0);//重設文件創建掩模 return; } 2. test.c清單 #include < stdio.h > #include < time.h > void init_daemon(void);//守護進程初始化函數 main() { FILE *fp; time_t t; init_daemon();//初始化為Daemon while(1)//每隔一分鐘向test.log報告運行狀態 { sleep(60);//睡眠一分鐘 if((fp=fopen("test.log","a")) >=0) { t=time(0); fprintf(fp,"Im here at %s/n",asctime(localtime(&t)) ); fclose(fp); } } }查看進程:ps -ef