殭屍進程是指它的父進程已經退出(父進程沒有等待(調用wait/waitpid)它),而該進程dead以後沒有進程接受,就成爲殭屍進程,也就是(zombie)進程。linux
一個進程在調用exit命令結束本身的生命的時候,其實它並無真正的被銷燬,而是留下一個稱爲殭屍進程(Zombie)的數據結構(系統調用exit,它的做用是使進程退出,但也僅僅限於將一個正常的進程變成一個殭屍進程,並不能將其徹底銷燬)。編程
在Linux進程的狀態中,殭屍進程是很是特殊的一種,它已經放棄了幾乎全部內存空間,沒有任何可執行代碼,也不能被調度,僅僅在進程列表中保留一個位置,記載該進程的退出狀態等信息供其餘進程收集,除此以外,殭屍進程再也不佔有任何內存空間。它須要它的父進程來爲它收屍。網絡
若是他的父進程沒安裝SIGCHLD信號處理函數調用wait或waitpid()等待子進程結束,又沒有顯式忽略該信號,那麼它就一直保持殭屍狀態,若是這時父進程結束了,那麼init進程自動會接手這個子進程,爲它收屍,它仍是能被清除的。數據結構
可是若是父進程是一個循環,不會結束,那麼子進程就會一直保持殭屍狀態,這就是爲何系統中有時會有不少的殭屍進程。系統所能使用的進程號是有限的,若是大量的產生僵死進程,將由於沒有可用的進程號而致使系統不能產生新的進程. 異步
以下代碼,子進程先於父進程退出,在父進程執行的5s內,子進程將爲殭屍:函數
#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> int main() { //子進程的pid int c_pid; int pid; if ((pid = fork())) { //父進程 c_pid = pid; printf("The child process is %d\n", c_pid); sleep(5); exit(0); } else { //子進程 printf("I 'm a child.\n"); exit(0); } }
打開終端並輸入下面命令:unix
ps aux | grep Z
code
會列出進程表中全部殭屍進程的詳細內容。繼承
正常狀況下咱們能夠用 SIGKILL 信號來殺死進程,可是殭屍進程已經死了, 你不能殺死已經死掉的東西。 所以你須要輸入的命令應該是:進程
ps -ef | grep pid
首先查看殭屍進程的父進程pid,輸出結果的第三列ppid就是父進程的pid
kill -s SIGCHLD ppid
將這裏的 pid 替換成父進程的進程 id,這樣父進程就會刪除全部以及完成並死掉的子進程了。
父進程調用waitpid()等函數來接收子進程退出狀態。
#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> #include <sys/wait.h> int main() { //子進程的pid int c_pid; int pid; if ((pid = fork())) { //父進程 c_pid = pid; printf("The child process is %d\n", c_pid); //阻塞等待子進程 int status; if ((pid = wait(&status)) != -1 && pid == c_pid) { //成功回收子進程 printf("The child exit with %d\n", WEXITSTATUS(status)); fflush(stdin); } printf("Now , The child has been exit , and I will sleep.\n"); sleep(20); exit(0); } else { //子進程 printf("I 'm a child.\n"); sleep(5); exit(0); } }
父進程先結束,子進程則自動託管到Init進程(pid = 1)。
#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> #include <sys/wait.h> int main() { //子進程的pid int c_pid; int pid; if ((pid = fork())) { //父進程 printf("I'm father id = %d.The child process is %d\n", getpid(), pid); exit(0); } else { //子進程 printf("I 'm a child.\n"); sleep(5); exit(0); } }
父進程一次fork()後產生一個子進程隨後當即執行waitpid(子進程pid, NULL, 0)來等待子進程結束,而後子進程fork()後產生孫子進程隨後當即exit(0)。這樣子進程順利終止(父進程僅僅給子進程收屍,並不須要子進程的返回值),而後父進程繼續執行。這時的孫子進程因爲失去了它的父進程(便是父進程的子進程),將被轉交給Init進程託管。因而父進程與孫子進程無繼承關係了,它們的父進程均爲Init,Init進程在其子進程結束時會自動收屍,這樣也就不會產生殭屍進程了。
#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> #include <sys/wait.h> int main() { //子進程的pid int c_pid; int pid; if ((pid = fork())) { //父進程 c_pid = pid; printf("I'm father id = %d.The child process is %d\n", getpid(), c_pid); //阻塞等待子進程 int status; if ((pid = wait(&status)) != -1 && pid == c_pid) { //成功回收子進程 printf("The child exit with %d\n", WEXITSTATUS(status)); fflush(stdin); } exit(0); } else { if ((pid = fork())) { //子進程 printf("I 'm a child pid = %d. my child pid = %d. exit.\n", getpid(), pid); exit(0); } else { //孫子進程 sleep(20); printf("I 'm a grandson pid = %d. exit\n", pid); exit(0); } } }
阻塞等待,那麼父進程就沒法作其餘事;
父進程退出,在建立守護進程時候會有,可是咱們並不想讓父進程退出;
fork()兩次,孤兒進程不易由咱們程序來管理;
man wait,查看NOTES章節,能夠找到:子進程退出的時候,會發送SIGCHLD信號,默認的POSIX不響應
因此設置處理SIGCHLD信號的函數,能夠用於異步回收fork子進程。
注意:信號產生觸發信號處理函數時,會中斷某些函數,例如poll、select、epoll等。
詳情見《unix網絡編程》5.8小節,POSIX信號處理
#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> #include <sys/wait.h> void sig_chld(int num) { pid_t pid; int stat; while ( (pid = waitpid(-1, &stat, WNOHANG)) > 0) // 循環處理完全部的信號 printf("child %d terminated\n", pid); return; } int main() { //子進程的pid int c_pid; int pid; signal(SIGCHLD, sig_chld); if ((pid = fork())) { //父進程 c_pid = pid; printf("The child process is %d\n", c_pid); //父進程不用等待,作本身的事情吧~ for (int i = 0; i < 10; i++) { printf("Do parent things.\n"); sleep(1); } exit(0); } else { //子進程 printf("I 'm a child.\n"); sleep(2); exit(0); } }
不推薦使用,由於POSIX標準中未規定SIG_IGN,會破壞程序的可移植性。
#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> #include <sys/wait.h> int main() { //子進程的pid int c_pid; int pid; signal(SIGCHLD,SIG_IGN); if ((pid = fork())) { //父進程 c_pid = pid; printf("The child process is %d\n", c_pid); //父進程不用等待,作本身的事情吧~ for (int i = 0; i < 10; i++) { printf("Do parent things.\n"); sleep(1); } exit(0); } else { //子進程 printf("I 'm a child.\n"); sleep(2); exit(0); } }