最近在看APUE,在進程式控制制章節中有個關於兩次fork防止進程僵死的列子很是不理解,經過一番研究發現原來原理很簡單,以下是執行個體:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <sys/wait.h> 4 5 int main(void) 6 { 7 pid_t pid; 8 if((pid = fork()) < 0) 9 { 10 printf("fork error\n"); 11 } 12 else if(pid == 0) 13 { 14 if((pid = fork()) < 0) 15 { 16 printf("fork error\n"); 17 } 18 else if(pid > 0) 19 { 20 exit(0); 21 } 22 sleep(5); 23 printf("second child, parent pid = %d\n", getppid()); 24 exit(0); 25 } 26 27 if(waitpid(pid, NULL, 0) != pid) 28 { 29 printf("waitpid error\n"); 30 } 31 exit(0); 32 }
執行結果:
上面的代碼大體思路如下:
1: 第8行第一次調用fork函數,產生一個子進程
2:第14行第二次調用fork函數在子進程中再產生個子進程,也就是孫進程咯
3:第18—21行是子進程執行exit函數使自己終止,而此時孫進程並為終止,所以孫進程由init進程領養,而init進程的任何一個子進程終止時都會調用wait函數去的起終止狀態,所以init進程不會產生僵死進程
4:子進程終止後,孫進程睡眠了5秒,然後列印孫進程的父進程ID也就是init進程ID:1,為什麼要睡眠5秒? 因為fork之後子進程和孫進程都可以繼續執行,而我們無法預知哪個先執行,我們要保證子進程先於孫進程終止,所以讓孫進程睡眠5秒
5:第27行,進程調用waitpid擷取子進程終止的狀態資訊,而使子進程也不會成為僵死進程
簡單的說,就是讓子進程產生孫進程,然後子進程終止,孫進程就變成init的子進程而不會成為僵死進程,而進程對終止的子進程做善後處理避免其變成僵死進程,這樣就避免了僵死進程的產生了
注意:程式執行的結果中,shell先列印了提示符,然後第二個子進程也就是孫進程列印器父進程ID,很顯然是進程先於孫進程終止