Как заставить дочерний процесс умереть после родительского выхода? - PullRequest
194 голосов
/ 12 ноября 2008

Предположим, у меня есть процесс, который порождает ровно один дочерний процесс. Теперь, когда родительский процесс завершается по какой-либо причине (обычно или ненормально, из-за kill, ^ C, подтверждения ошибки или чего-то еще), я хочу, чтобы дочерний процесс умер Как это сделать правильно?


Некоторые похожие вопросы по stackoverflow:


Некоторые похожие вопросы по стеку потока для Windows :

Ответы [ 23 ]

0 голосов
/ 26 ноября 2013

Я нашел 2 решения, оба не идеальные.

1. Убить всех детей с помощью kill (-pid) при получении сигнала SIGTERM.
Очевидно, что это решение не может обрабатывать «kill -9», но оно работает для большинства случаев и очень просто, потому что ему не нужно запоминать все дочерние процессы.


    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();
      });
    }

Таким же образом, вы можете установить обработчик 'exit', как описано выше, если вы вызываете process.exit где-нибудь. Примечание: Ctrl + C и внезапный сбой автоматически обрабатываются ОС для уничтожения группы процессов, поэтому здесь больше нет.

2.Используйте chjj / pty.js для запуска процесса с подключенным управляющим терминалом.
Когда вы в любом случае уничтожаете текущий процесс, даже уничтожая -9, все дочерние процессы также будут автоматически уничтожаться (ОС?). Я предполагаю, что поскольку текущий процесс удерживает другую сторону терминала, поэтому, если текущий процесс умирает, дочерний процесс получит SIGPIPE, поэтому он умрет.


    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 голосов
/ 06 декабря 2017

Другой способ сделать это, специфичный для Linux, - создать родителя в новом пространстве имен PID. Тогда это будет PID 1 в этом пространстве имен, и когда он выйдет из него, все его дети будут немедленно убиты с SIGKILL.

К сожалению, для создания нового пространства имен PID необходимо иметь CAP_SYS_ADMIN. Но этот метод очень эффективен и не требует никаких реальных изменений для родителей или детей после первоначального запуска родителя.

См. клон (2) , pid_namespaces (7) и unshare (2) .

0 голосов
/ 07 декабря 2011

Если родитель умирает, PPID сирот изменится на 1 - вам нужно только проверить свой PPID. В некотором смысле, это опрос, упомянутый выше. вот кусок оболочки для этого:

check_parent () {
      parent=`ps -f|awk '$2=='$PID'{print $3 }'`
      echo "parent:$parent"
      let parent=$parent+0
      if [[ $parent -eq 1 ]]; then
        echo "parent is dead, exiting"
        exit;
      fi
}


PID=$$
cnt=0
while [[ 1 = 1 ]]; do
  check_parent
  ... something
done
...