2013-07-11 142 views
5

我有一個C++程序,充當其他人的看門狗。如果它檢測到一個進程不再運行,它將通過system重新啓動它。問題是,如果我殺了看門狗進程,它啓動的任何進程也會死掉。如何生成不會與父母一起死亡的子進程?

void* ProcessWatchdog::worker(void* arg) 
{ 
    //Check if process is running 
    if(!processRunning) 
     system("processName /path/to/processConfig.xml &"); 
} 

新的子進程正常啓動,運行沒有任何問題。但是當父母(現在這個ProcessWatchdog過程)死亡時,孩子也死了。我如何產生一個完全獨立於父代的子進程?

我試過使用pclosepopen,運行啓動進程的shell腳本和其他一些策略,但都無濟於事。我忽略了子進程中的SIGHUP信號,但它們仍然死亡。

所以理想情況下,我想告訴系統啓動一個完全獨立於父系的進程。我希望孩子的trace以孩子結束,並且系統不知道ProcessWatchdog首先啓動它。

有沒有一種方法可以做到這一點?

我正在用C++寫在Linux上。

+0

[使子系統產生的子進程()繼續運行後,父母獲取殺死信號和退出]可能的重複(http://stackoverflow.com/questions/12945189/make-child-進程產生與系統保持運行後父母得到殺死sig) –

+0

我不認爲使用系統是一個好主意.... – Alexis

+0

爲什麼不使用系統一個好主意?除了明顯的安全問題?我在一個非常受控制的環境中在嵌入式系統上執行此操作,並且我不擔心錯誤的系統調用。我應該警惕另一個原因嗎? –

回答

0

嘗試使用systemsetsid進程名之前。

system("setsid processname /path/to/processConfig.xml &"); 

這將在新的會話中啓動程序。

3

不要使用system(...)它不是多線程安全的。

int pid = fork(); 

if(pid==0) 
{ 
    int rc = execv("processname", "/path/to/processConfig.xml &"); 
    if(rc == -1) 
    { 
    printf(stderr, "processname failed to start. %d", errno); 
    } 
    ... 
} 
else 
{ 
    //continue with the parent 
} 
+3

您可否詳細說明'不是多線程安全'? –

+0

execv在第二個參數中需要char ** – Alexis

1

您應該避免使用系統。

不要從一個程序設置用戶ID或設置組ID 特權使用system(),因爲一些環境變量 奇怪的值可能被用來破壞系統的完整性。改爲使用exec(3)系列 函數。

,如果你想檢查返回值或其他任何

只是去execl

#include <unistd.h> 
#include <stdlib.h> 
pid_t pid = fork() 
if (pid == -1) 
{ 
    exit(EXIT_FAILURE); 
} 
else if (pid == 0) 
{ 
    if (execl("processname", "processname", "/path/to/processConfig.xml", NULL) == -1) 
    exit(EXIT_FAILURE); 
} 
else 
... 
4

這是一個有點老,但沒有得到完整的答案。下面是我在嵌入式系統上完成的一項工作,它生成一個與父項無關的bash子項。請注意,我運行一個bash shell,然後在另一個bash shell中運行我的命令。在你的情況下這可能不是必要的。對我來說,它允許我做一些I/O重定向,如果沒有它,它將無法正常工作。

兩個重要的概念是setsid()和雙叉()。這兩者的組合可以防止孤兒在完成時創建殭屍,並且可以防止父母完成後孤兒被殺。

還有很多其他問題可能出現,如繼承的I/O句柄,工作目錄等,但此代碼完成基本工作。

int spawn_orphan(char* cmd) { 
    char command[1024]; // We could segfault if cmd is longer than 1000 bytes or so 
    int pid; 
    int Stat; 
    pid = fork(); 
    if (pid < 0) { perror("FORK FAILED\n"); return pid; } 
    if (pid == 0) { // CHILD 
     setsid(); // Make this process the session leader of a new session 
     pid = fork(); 
     if (pid < 0) { printf("FORK FAILED\n"); exit(1); } 
     if (pid == 0) { // GRANDCHILD 
      sprintf(command,"bash -c '%s'",cmd); 
      execl("/bin/bash", "bash", "-c", command, NULL); // Only returns on error 
      perror("execl failed"); 
      exit(1); 
     } 
     exit(0); // SUCCESS (This child is reaped below with waitpid()) 
    } 

    // Reap the child, leaving the grandchild to be inherited by init 
    waitpid(pid, &Stat, 0); 
    if (WIFEXITED(Stat) && (WEXITSTATUS(Stat) == 0)) { 
     return 0; // Child forked and exited successfully 
    } 
    else { 
     perror("failed to spawn orphan\n"); 
     return -1; 
    } 
} 
相關問題