2014-02-13 90 views
1

假設我有一個產生少量工人(子進程)的父進程。 我希望得到通知時,其中一個子進程崩潰(被殺害)。當子進程死亡時通知父進程

什麼是獲得此通知的最佳方式。 我用c或C++編程。 我在unix上。並催生了使用fork_and_exec

回答

3

如果興田子進程只希望得到通知時,子進程退出(正常或異常),你可以寫一個處理程序,以SIGCHLD在父進程信號。只要該進程產生的進程死亡,該處理程序就會執行。

但是,你可以在這個處理程序裏面做什麼有嚴重的限制。在收到其他信號的情況下,該處理程序將立即中斷。即使變量賦值不是信號處理程序內部的安全操作 - 賦值可能需要兩個或更多的機器指令,並且可能會被新信號中斷,從而使值不確定。在信號處理程序內可安全分配的唯一變量是sig_atomic_t(賦予此類型的變量保證在一條指令中完成)。

父母還必須對子進程「等待」(使用等待函數) - 否則子進程終止後將變爲殭屍。

這個解決方案對我來說已經足夠了,因爲我只需要減少sig_atomic_t類型的計數器變量。如果孩子死後需要做一些「嚴肅」的處理,則需要其他解決方案。這個想法可能是如下:

  • 在這個主過程中,有一個專門的線程,將等待兒童死亡(這包括成功地從main返回,由SIGTERM和SIGKILL信號和任何其他異常終止被殺) 。
  • 爲此,我們可以使用UNIX waitid()方法,讓我們指定我們正在等待的孩子,我們正在等待的事件類型(EXITED,STOPPED或CONTINUED),並且在成功時爲我們提供了關於終止過程(如孩子的PID)。
  • 因此,在這個線程中,我們使用了waitid()來等待孩子,每次孩子死亡這個函數終止給我們提供有用的信息。
  • waitid()返回後,我們應該檢查它的返回值和errno,看看是否一切正常。如果是的話,我們可以執行我們的清理程序(我們希望在孩子死亡時執行的代碼塊),然後我們繼續聽更多的死亡(聽起來很糟糕)。

C++樣本可以發現如下 - 請注意我不使用一個線程等待的孩子,但它不應該是很難修改的例子使用一個線程。

#include <iostream> 
#include <sys/types.h> 
#include <unistd.h> 

int spawn(char* process_name, char** arguments){ 
    pid_t child_id = fork(); 

    if (child_id != 0) 
     return child_id; 
    else{ 
     execvp(process_name, arguments); 
     fprintf(stderr, "An error occured while executing new process.\n"); 
     abort(); 
    } 
} 


int main(int argc, const char * argv[]) 
{ 
    char* arguments[] = { 
     "/Path_to_Child_Exe/Child_Process", 
     nullptr 
    }; 

    int i=0; 
    while (i++ < 10) 
     spawn((char*) "/Path_to_Child_Exe/Child_Process", arguments); 


    while (true){ 
     siginfo_t exit_info; 
     int retVal = waitid(P_ALL, -1, &exit_info, WEXITED); 

     if (retVal == -1 && errno == ECHILD){ 
      std::cout << "No more children.\n"; 
      break; 
     } 

     std::cout << "Child with PID " << exit_info.si_pid << " terminated.\n"; 

     sleep(1); 
    } 

    return 0; 
} 

同樣重要的是要注意到,我們在while循環的每次迭代結束調用sleep。在等待孩子的線程中也應該這樣做。否則,如果我們在沒有子進程的情況下調用waitid()函數而沒有暫停,則CPU使用率會非常高(我猜測是一種繁忙的等待形式)。因此,我們必須每隔一段時間調用一次睡眠,讓CPU有機會休息。