什麼是殭屍進程?
首先內核會釋放終止進程(調用了exit系統調用)所使用的所有存儲區,關閉所有打開的文件等,但內核爲每一個終止子進程保存了一定量的信息。這些信息至少包括進程ID,進程的終止狀態,以及該進程使用的CPU時間,所以當終止子進程的父進程調用wait或waitpid時就可以得到這些信息。
而殭屍進程就是指:一個進程執行了exit系統調用退出,而其父進程並沒有爲它收屍(調用wait或waitpid來獲得它的結束狀態)的進程。
任何一個子進程(init除外)在exit後並非馬上就消失,而是留下一個稱外殭屍進程的數據結構,等待父進程處理。這是每個子進程都必需經歷的階段。另外子進程退出的時候會向其父進程發送一個SIGCHLD信號。
如何避免殭屍進程
通過signal(SIGCHLD, SIG_IGN)通知內核對子進程的結束不關心,由內核回收
父進程調用wait/waitpid等函數等待子進程結束,如果尚無子進程退出wait會導致父進程阻塞。waitpid可以通過傳遞WNOHANG使父進程不阻塞立即返回。
如果父進程很忙可以用signal註冊信號處理函數,在信號處理函數調用wait/waitpid等待子進程退出。
通過兩次調用fork。父進程首先調用fork創建一個子進程然後waitpid等待子進程退出,子進程再fork一個孫進程後退出。這樣子進程退出後會被父進程等待回收,而對於孫子進程其父進程已經退出所以孫進程成爲一個孤兒進程,孤兒進程由init進程接管,孫進程結束後,init會等待回收。
如以下代碼會創建100個子進程,但是父進程並未等待它們結束,所以在父進程退出前會有100個殭屍進程。
C
#include <stdio.h>
#include <unistd.h>
int main() {
int i;
pid_t pid;
for(i=0; i<100; i++) {
pid = fork();
if(pid == 0)
break;
}
if(pid>0) {
printf("press Enter to exit...");
getchar();
}
return 0;
}
其中一個解決方法即是編寫一個SIGCHLD信號處理程序來調用wait/waitpid來等待子進程返回。
C
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
void wait4children(int signo) {
int status;
wait(&status);
}
int main() {
int i;
pid_t pid;
signal(SIGCHLD, wait4children);
for(i=0; i<100; i++) {
pid = fork();
if(pid == 0)
break;
}
if(pid>0) {
printf("press Enter to exit...");
getchar();
}
return 0;
}
但是通過運行程序發現還是會有殭屍進程,而且每次殭屍進程的數量都不定。這是爲什麼呢?其實主要是因爲Linux的信號機制是不排隊的,假如在某一時間段多個子進程退出後都會發出SIGCHLD信號,但父進程來不及一個一個地響應,所以最後父進程實際上只執行了一次信號處理函數。但執行一次信號處理函數只等待一個子進程退出,所以最後會有一些子進程依然是殭屍進程。
雖然這樣但是有一點是明瞭的,就是收到SIGCHLD必然有子進程退出,而我們可以在信號處理函數裏循環調用waitpid函數來等待所有的退出的子進程。至於爲什麼不用wait,主要原因是在wait在清理完所有殭屍進程後再次等待會阻塞。
所以最佳方案(個人觀點)如下:
C
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
void wait4children(int signo) {
int status;
while(waitpid(-1, &status, WNOHANG) > 0);
}
int main() {
int i;
pid_t pid;
signal(SIGCHLD, wait4children);
for(i=0; i<100; i++) {
pid = fork();
if(pid == 0)
break;
}
if(pid>0) {
printf("press Enter to exit...");
getchar();
}
return 0;
}
wait WNOHANG 殭屍進程
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章
UDP點對點併發通信
JDSH0224
2020-07-05 02:17:23
socket編程(inet_ntoa、inet_addr、htol、htos)
JDSH0224
2020-07-05 02:17:23
linux高性能服務器編程學習筆記一:TCP/IP協議詳解
weixin_37924880
2020-06-28 19:25:12
linux網絡編程學習筆記(3)——套接字選項編程
li_wen01
2020-06-21 18:58:02
TCP併發服務器設計
yff1030
2020-06-16 14:35:26
網卡介紹——MAC與PHY的關係分析
li_wen01
2020-05-15 00:24:04
linux iptabes
JDSH0224
2020-03-06 02:37:06
linux ioctl 應用詳解
zgs2014
2020-02-25 15:14:33
linux 網絡編程基礎(四)read,write,connect超時封裝
zgs2014
2020-02-25 15:14:33
getsockopt()與setsockopt()函數 測試代碼
zgs2014
2020-02-25 15:14:33
linux網絡編程基礎(二)
zgs2014
2020-02-25 15:14:33
sockaddr_in , sockaddr , in_addr區別
zgs2014
2020-02-25 15:14:23
基於TCP的socket編程設計
yff1030
2020-02-23 17:57:39