2013-02-20 21 views
1

我有一個長時間運行的進程(node.js),它調用fork(作爲C++模塊的一部分)。這將創建新進程作爲node.js進程的子進程。然而,這個子進程沒有什麼會等待/ waitpid,所以它在終止後仍然是殭屍。fork一個長時間運行的進程,並避免不得不調用waitpid來清理殭屍?

是否有可能fork()一個進程沒有當前進程是其父,所以在終止時,它不會保持在殭屍狀態,但被清理?

如果不是,我可以以某種方式表明我不會對孩子調用waitpid並且不關心它何時終止?

做不到這一切,我可以寫/查找本機模塊,可以做的waitpid函數,但我需要確定它會:

  1. 沒有擋住父進程(node.js的)
  2. 模塊功能調用後不留任何殭屍

謝謝!

+1

只是'fork'兩次。長時間運行的進程現在會有它的父進程(第一個子進程)死掉,並且會被'init' [[它將收穫它]]繼承(http://stackoverflow.com/a/881434/721269)。 – 2013-02-20 02:29:43

+1

或者在某些Unix上,您可以將'SIGCHLD'設置爲'SIG_IGN',並且內核會將其解釋爲您希望殭屍立即消失,而您對其退出狀態不感興趣。 – zwol 2013-02-20 02:31:44

+2

@David:所以第一個fork會創建子進程C1(父進程是node.js進程),然後fork C1來創建C2,這是我想被init繼承的進程? C1幾乎會立即死亡,node.js然後需要在C1上waitpid(我們知道它會很快),然後C2被init繼承。我理解正確嗎? – Pavel 2013-02-20 02:35:09

回答

3

下面是我用來創建守護進程的代碼。意見描述爲什麼每一步都完成了。

Status daemon_init(void) 
{ 
    pid_t pid; 
    int fh; 

    /*----------------------------------------------------------------------- 
    ; From the Unix Programming FAQ (corraborated by Stevens): 
    ; 
    ; 1. 'fork()' so the parent can exit, this returns control to the command 
    ; line or shell invoking your program. This step is required so that 
    ; the new process is guaranteed not to be a process group leader. The 
    ; next step, 'setsid()', fails if you're a process group leader. 
    ;---------------------------------------------------------------------*/ 

    pid = fork(); 
    if (pid == (pid_t)-1) 
    return retstatus(false,errno,"fork()"); 
    else if (pid != 0) /* parent goes bye bye */ 
    _exit(EXIT_SUCCESS); 

    /*------------------------------------------------------------------------- 
    ; 2. 'setsid()' to become a process group and session group leader. Since 
    ; a controlling terminal is associated with a session, and this new 
    ; session has not yet acquired a controlling terminal our process now 
    ; has no controlling terminal, which is a Good Thing for daemons. 
    ; 
    ; _Advanced Programming in the Unix Environment_, 2nd Edition, also 
    ; ignores SIGHUP. So adding that here as well. 
    ;-----------------------------------------------------------------------*/ 

    setsid(); 
    set_signal_handler(SIGHUP,SIG_IGN); /* ignore this signal for now */ 

    /*------------------------------------------------------------------------- 
    ; 3. 'fork()' again so the parent, (the session group leader), can exit. 
    ; This means that we, as a non-session group leader, can never regain a 
    ; controlling terminal. 
    ;------------------------------------------------------------------------*/ 

    pid = fork(); 
    if (pid == (pid_t)-1) 
    return retstatus(false,errno,"fork(2)"); 
    else if (pid != 0) /* parent goes bye bye */ 
    _exit(EXIT_SUCCESS); 

    /*------------------------------------------------------------------------- 
    ; 4. 'chdir("/")' to ensure that our process doesn't keep any directory in 
    ; use. Failure to do this could make it so that an administrator 
    ; couldn't unmount a filesystem, because it was our current directory. 
    ; 
    ; [Equivalently, we could change to any directory containing files 
    ; important to the daemon's operation.] 
    ; 
    ; I just made sure the name of the script we are using contains the full 
    ; path. 
    ;-------------------------------------------------------------------------*/ 

    chdir("/"); 

    /*----------------------------------------------------------------------- 
    ; 5. 'umask(022)' so that we have complete control over the permissions of 
    ; anything we write. We don't know what umask we may have inherited. 
    ;-----------------------------------------------------------------------*/ 

    umask(022); 

    /*----------------------------------------------------------------------- 
    ; 6. 'close()' fds 0, 1, and 2. This releases the standard in, out, and 
    ; error we inherited from our parent process. We have no way of knowing 
    ; where these fds might have been redirected to. Note that many daemons 
    ; use 'sysconf()' to determine the limit '_SC_OPEN_MAX'. 
    ; '_SC_OPEN_MAX' tells you the maximun open files/process. Then in a 
    ; loop, the daemon can close all possible file descriptors. You have to 
    ; decide if you need to do this or not. If you think that there might 
    ; be file-descriptors open you should close them, since there's a limit 
    ; on number of concurrent file descriptors. 
    ; 
    ; 7. Establish new open descriptors for stdin, stdout and stderr. Even if 
    ; you don't plan to use them, it is still a good idea to have them 
    ; open. The precise handling of these is a matter of taste; if you 
    ; have a logfile, for example, you might wish to open it as stdout or 
    ; stderr, and open '/dev/null' as stdin; alternatively, you could open 
    ; '/dev/console' as stderr and/or stdout, and '/dev/null' as stdin, or 
    ; any other combination that makes sense for your particular daemon. 
    ; 
    ; We do this here via dup2(), which combines steps 6 & 7. 
    ;------------------------------------------------------------------------*/ 

    fh = open(DEV_NULL,O_RDWR); 
    if (fh == -1) 
    return retstatus(false,errno,"open(" DEV_NULL ")"); 

    assert(fh > 2); 

    dup2(fh,STDIN_FILENO); 
    dup2(fh,STDOUT_FILENO); 
    dup2(fh,STDERR_FILENO); 

    close(fh); 

    return c_okay; 
} 

如果你想看到在上下文中此功能,您可以在這裏查看:https://github.com/spc476/syslogintr/blob/master/syslogintr.c

+0

步驟6和7應該發生在步驟1和步驟2之間;此外,您應該在此時發出'closefrom(3)'或等價物。在一些(舊的)系統中,如果你有一個指向終端的開放fd,'setsid'會失敗。 – zwol 2013-02-20 14:17:17