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

穆晨發表於2017-01-28

前言

       如果父程式沒有結束,而子程式終止了。那麼在父程式呼叫 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,而是因為子程式終止後,其一些資訊作業系統或者使用者以後還可能會用到。

相關文章