第十九篇:處理僵屍進程的兩種經典方法


前言

       如果父進程沒有結束,而子進程終止了。那么在父進程調用 wait 函數回收這個子進程或者父進程終止以前,這個子進程將一直是僵屍進程

       本文將提供兩種方法處理這個問題。

方法一:父進程回收法

       wait函數將使其調用者阻塞,直到其某個子進程終止。故父進程可調用wait函數回收其僵屍子進程。除此之外,waitpid函數提供更為詳盡的功能( 增加了非阻塞功能以及指定等待功能 ),請讀者自行查閱相關資料。

代碼實現

 1 #include <unistd.h>
 2 #include <sys/wait.h>
 3 #include <stdio.h>
 4 #include <stdlib.h>
 5 
 6 int main()
 7 {
 8     int pid;
 9     int *status;
10 
11     printf("%s\n", "啟動父進程");
12 
13     if ((pid = fork()) < 0) {
14         printf("%s\n", "創建子進程失敗");
15         exit(1);
16     }
17     else 
18         if (pid ==0) {
19             printf("%s\n", "進入子進程");
20             sleep(4);
21             // 終止子進程
22             exit(0);
23         }
24     else {
25         // 進入父進程
26         // 回收僵屍子子進程
27         wait(status);
28         printf("%s\n", "回收完畢");
29     }
30 
31     exit(0);
32 }

運行測試

       

結果分析

       第三行的“回收完畢”是在程序執行四秒后才顯示的。這說明盡管我將子進程阻塞了4秒,父進程並不會先於子進程終止。因為它調用了wait函數,故需要等待一個子進程結束並將其回收,否則就一直阻塞在那里。

方法二:init進程回收法

       上面的這種解決方案需要父進程去等待子進程,但在很多情況下,這並不合適,因為父進程也許還有其他任務要做,不能阻塞在這里。在講述下面這種不用父進程等待就能完成回收子進程的方法之前,先請明白以下兩個概念:

       1. 如果父進程先於子進程結束,那么子進程的父進程自動改為 init 進程。

       2. 如果 init 的子進程結束,則 init 進程會自動回收其子進程的資源而不是讓它變成僵屍進程。

代碼實現

 1 #include "apue.h"
 2 #include <sys/wait.h>
 3 
 4 int
 5 main(void)
 6 {
 7     pid_t    pid;
 8 
 9     if ((pid = fork()) < 0) {    // 創建第一個子進程
10         err_sys("fork error");
11     } else if (pid == 0) {    // 進入第一個子進程
12         if ((pid = fork()) < 0)    // 創建第二個子進程
13             err_sys("fork error");
14         else if (pid > 0) // 進入第一個子進程 
15             exit(0);    // 終止第一個子進程    
16         // 第二個子進程在睡眠2S后才執行,這樣一般情況下第一個子進程會先終止。
17         sleep(2);
18         // 這時,第一個子進程肯定終止了,那么它的父進程就自動變成了init。
19         printf("second child, parent pid = %d\n", getppid());
20         exit(0);
21     }
22 
23     // 父進程等待並回收第一個子進程
24     if (waitpid(pid, NULL, 0) != pid)    
25         err_sys("waitpid error");
26 
27     // 父進程執行到這里以后,可以退出,也可以執行其他的任務。
28     // 對於剛才那第二個子進程,它繼承了父進程的資源,同時它終止后也會被init進程回收,
29     // 不會成為僵屍進程。
30     exit(0);
31 }

說明

       1. fork創建子進程以后,子進程擁有的是父進程的一個資源副本,而不是和它共享資源。

       2. 子進程終止后變成僵屍進程並不是系統BUG,而是因為子進程終止后,其一些信息操作系統或者用戶以后還可能會用到。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM