How to make child process die after parent exits?

后端 未结 24 1723
天涯浪人
天涯浪人 2020-11-22 05:31

Suppose I have a process which spawns exactly one child process. Now when the parent process exits for whatever reason (normally or abnormally, by kill, ^C, assert failure o

相关标签:
24条回答
  • 2020-11-22 06:19

    I don't believe it's possible to guarantee that using only standard POSIX calls. Like real life, once a child is spawned, it has a life of its own.

    It is possible for the parent process to catch most possible termination events, and attempt to kill the child process at that point, but there's always some that can't be caught.

    For example, no process can catch a SIGKILL. When the kernel handles this signal it will kill the specified process with no notification to that process whatsoever.

    To extend the analogy - the only other standard way of doing it is for the child to commit suicide when it finds that it no longer has a parent.

    There is a Linux-only way of doing it with prctl(2) - see other answers.

    0 讨论(0)
  • 2020-11-22 06:20

    I think a quick and dirty way is to create a pipe between child and parent. When parent exits, children will receive a SIGPIPE.

    0 讨论(0)
  • 2020-11-22 06:20

    I found 2 solutions, both not perfect.

    1.Kill all children by kill(-pid) when received SIGTERM signal.
    Obviously, this solution can not handle "kill -9", but it do work for most case and very simple because it need not to remember all child processes.

    
        var childProc = require('child_process').spawn('tail', ['-f', '/dev/null'], {stdio:'ignore'});
    
        var counter=0;
        setInterval(function(){
          console.log('c  '+(++counter));
        },1000);
    
        if (process.platform.slice(0,3) != 'win') {
          function killMeAndChildren() {
            /*
            * On Linux/Unix(Include Mac OS X), kill (-pid) will kill process group, usually
            * the process itself and children.
            * On Windows, an JOB object has been applied to current process and children,
            * so all children will be terminated if current process dies by anyway.
            */
            console.log('kill process group');
            process.kill(-process.pid, 'SIGKILL');
          }
    
          /*
          * When you use "kill pid_of_this_process", this callback will be called
          */
          process.on('SIGTERM', function(err){
            console.log('SIGTERM');
            killMeAndChildren();
          });
        }
    
    

    By same way, you can install 'exit' handler like above way if you call process.exit somewhere. Note: Ctrl+C and sudden crash have automatically been processed by OS to kill process group, so no more here.

    2.Use chjj/pty.js to spawn your process with controlling terminal attached.
    When you kill current process by anyway even kill -9, all child processes will be automatically killed too (by OS?). I guess that because current process hold another side of the terminal, so if current process dies, the child process will get SIGPIPE so dies.

    
        var pty = require('pty.js');
    
        //var term =
        pty.spawn('any_child_process', [/*any arguments*/], {
          name: 'xterm-color',
          cols: 80,
          rows: 30,
          cwd: process.cwd(),
          env: process.env
        });
        /*optionally you can install data handler
        term.on('data', function(data) {
          process.stdout.write(data);
        });
        term.write(.....);
        */
    
    
    0 讨论(0)
  • 2020-11-22 06:21

    I've passed parent pid using environment to the child, then periodically checked if /proc/$ppid exists from the child.

    0 讨论(0)
  • 2020-11-22 06:22

    Another way to do this that is Linux specific is to have the parent be created in a new PID namespace. It will then be PID 1 in that namespace, and when it exits it all of it's children will be immediately killed with SIGKILL.

    Unfortunately, in order to create a new PID namespace you have to have CAP_SYS_ADMIN. But, this method is very effective and requires no real change to the parent or the children beyond the initial launch of the parent.

    See clone(2), pid_namespaces(7), and unshare(2).

    0 讨论(0)
  • 2020-11-22 06:25

    As other people have pointed out, relying on the parent pid to become 1 when the parent exits is non-portable. Instead of waiting for a specific parent process ID, just wait for the ID to change:

    pit_t pid = getpid();
    switch (fork())
    {
        case -1:
        {
            abort(); /* or whatever... */
        }
        default:
        {
            /* parent */
            exit(0);
        }
        case 0:
        {
            /* child */
            /* ... */
        }
    }
    
    /* Wait for parent to exit */
    while (getppid() != pid)
        ;
    

    Add a micro-sleep as desired if you don't want to poll at full speed.

    This option seems simpler to me than using a pipe or relying on signals.

    0 讨论(0)
提交回复
热议问题