轉(zhuǎn)自:http://www./blog/archives/599 有些日子沒(méi)有跟工程師一起工作了,。昨天星期五,,我回到川崎的辦公室和同事一起結(jié)果一個(gè)客戶反饋的問(wèn)題。這個(gè)工作卻又讓我懷念以前作研發(fā)的那些時(shí)光,。突然覺(jué)得有些東西還是不應(yīng)該被忘記,,就寫(xiě)在這里作筆記了。 守護(hù)進(jìn)程(Daemon)守護(hù)進(jìn)程——我情愿把他叫做精靈進(jìn)程——是多種操作系統(tǒng)中的一種常駐程序,。常駐的意思是,在系統(tǒng)運(yùn)行期間,,這些進(jìn)程都一直存在,。很明顯,,大多數(shù)服務(wù)器程序都是精靈進(jìn)程,。在這里我要說(shuō)一說(shuō)自己知道關(guān)于精靈進(jìn)程的方法,,和與此相關(guān)的一些技巧。 如何產(chǎn)生一個(gè)精靈進(jìn)程,?Linux系統(tǒng)啟動(dòng)以后,,它通常啟動(dòng)的第一個(gè)進(jìn)程就是init進(jìn)程。init進(jìn)程的進(jìn)程ID是1,,并且它會(huì)一直在系統(tǒng)運(yùn)行期間存續(xù),。同 時(shí),,Linux對(duì)進(jìn)程的管理策略有兩個(gè)比較特殊的地方,,其中之一就是,,當(dāng)一個(gè)進(jìn)程的父進(jìn)程結(jié)束,它的子進(jìn)程如果還繼續(xù)運(yùn)行,,那么,,子進(jìn)程就會(huì)被init進(jìn) 程收養(yǎng),。也算就是說(shuō),,Linux對(duì)進(jìn)程的管理策略,,其實(shí)是一直在努力維護(hù)一棵樹(shù),。利用這一點(diǎn),就可產(chǎn)生伴隨init一直存在的精靈進(jìn)程,。代碼例子如下: /* file: daemon_sample.c */#include #include #include #include int main () { pid_t pid,sid; /* fork to leave parent */ pid = fork (); if (pid < 0) { printf ("failed to fork!\n"); exit (EXIT_FAILURE); } else if (pid > 0) { /* parent process go to exit */ exit (EXIT_SUCCESS); } /* child process */ chdir("/"); sid = setsid (); if (sid < 0) { printf ("Failed to set session id.\n"); exit (EXIT_FAILURE); } /* ensure all files created by itself are accessible */ umask (0); printf ("Daemon adopted by parent %d\n", getppid()); /* daemon loop */ while (1) { sleep (1); } } 產(chǎn)生一個(gè)精靈進(jìn)程的過(guò)程需要有一下幾步:
這是一個(gè)非常簡(jiǎn)單的例子,,通常情況下,,子進(jìn)程還需要關(guān)閉標(biāo)準(zhǔn)輸入輸出等等工作。與此相關(guān)的詳細(xì)討論可以查看 恩,,奇怪的地方就在與此了,。如果用如下命令編譯上面的簡(jiǎn)短程序,,你會(huì)發(fā)現(xiàn)一處不太符合想象的地方,。 換句話說(shuō),,不能使用getppid來(lái)判斷一個(gè)進(jìn)程時(shí)候是精靈進(jìn)程,。那么,應(yīng)該怎樣判斷,? 再看上面ps的輸出結(jié)果,,你會(huì)發(fā)現(xiàn)這個(gè)進(jìn)程的tty域是一個(gè)問(wèn)號(hào)。這表明,,該進(jìn)程并沒(méi)有被attach到任何終端設(shè)備上去,。事實(shí)上所有的精靈進(jìn)程都有這個(gè)特性。利用ps做一個(gè)驗(yàn)證吧,。 printf ("This is a daemon\n"); } else { printf ("This is not a daemon\n"); } 在UNIX論壇上有一個(gè)關(guān)于這個(gè)話題的舊帖子,地址如下: 僵尸進(jìn)程其實(shí)是個(gè)錯(cuò)誤,。 這個(gè)錯(cuò)誤產(chǎn)生的原因在于,子進(jìn)程已經(jīng)結(jié)束,,但是父進(jìn)程卻沒(méi)有對(duì)它進(jìn)行清理,。僵尸進(jìn)程會(huì)被init收編,,并且init會(huì)料理這些僵尸的“善后事宜”。我們可以寫(xiě)一個(gè)很蹩腳的程序來(lái)產(chǎn)生一個(gè)貨真價(jià)實(shí)的僵尸進(jìn)程,。僵尸來(lái)了,! /* file: zombie.c */#include #include #include int main () { pid_t child_pid; /* Create a child process. */ child_pid = fork (); if (child_pid > 0) { /* This is the parent process. Sleep for a minitue. */ sleep (60); } else { /* This is the child process. Exit immediately. */ exit (EXIT_SUCCESS); } return 0; } 編譯并運(yùn)行這個(gè)程序,在程序運(yùn)行期間,,利用ps查看它的狀態(tài),,你會(huì)得到下面的結(jié)果: 在一般的桌面系統(tǒng)上,即使產(chǎn)生僵尸進(jìn)程也不是什么大不了的事情,,因?yàn)?,系統(tǒng)資源并不緊張的情況下,僵尸最終會(huì)被init清理,。但是,,在高負(fù)載的服務(wù) 器或者資源非常有限的嵌入式系統(tǒng)中如果大量出現(xiàn)僵尸,那會(huì)是個(gè)一個(gè)麻煩,。所以,,避免產(chǎn)生僵尸進(jìn)程的方法就是在父進(jìn)程中正確的處理wait和SIGCHLD 信號(hào),具體做法google一下可以出很多結(jié)果,,這里就不再累述了,。 |
|
來(lái)自: 紫火神兵 > 《網(wǎng)絡(luò)編程》