Как заставить дочерний процесс умереть после завершения родительского процесса?

StackOverflow https://stackoverflow.com/questions/284325

  •  08-07-2019
  •  | 
  •  

Вопрос

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


Какой-то похожий вопрос по stackoverflow:


Какой-то похожий вопрос по stackoverflow для Windows:

Это было полезно?

Решение

Дочерний элемент может попросить ядро доставить SIGHUP (или другой сигнал), когда родитель умирает, указав опцию PR_SET_PDEATHSIG в prctl() системный вызов, подобный этому:

prctl(PR_SET_PDEATHSIG, SIGHUP);

Видишь man 2 prctl для получения подробной информации.

Редактировать:Это доступно только для Linux

Другие советы

Я пытаюсь решить ту же проблему, и поскольку моя программа должна работать на OS X, решение только для Linux у меня не сработало.

Я пришел к тому же выводу, что и другие люди на этой странице - не существует совместимого с POSIX способа уведомления дочернего элемента о смерти родителя.Итак, я придумал следующую лучшую вещь - провести детский опрос.

Когда родительский процесс умирает (по любой причине), родительский процесс дочернего процесса становится процессом 1.Если дочерний элемент просто периодически опрашивает, он может проверить, равен ли его родительский элемент 1.Если это так, то ребенок должен выйти.

Это не очень здорово, но это работает, и это проще, чем решения для опроса TCP socket / lockfile, предложенные в другом месте на этой странице.

Я достиг этого в прошлом, запустив "исходный" код в "дочернем" и "порожденный" код в "родительском" (то есть:вы переворачиваете обычный смысл теста после fork()).Затем перехватите SIGCHLD в "порожденном" коде...

Возможно, в вашем случае это невозможно, но мило, когда это работает.

Если вы не можете изменить дочерний процесс, вы можете попробовать что-то вроде следующего:

int pipes[2];
pipe(pipes)
if (fork() == 0) {
    close(pipes[1]); /* Close the writer end in the child*/
    dup2(0, pipes[0]); /* Use reader end as stdin */
    exec("sh -c 'set -o monitor; child_process & read dummy; kill %1'")
}

close(pipes[0]); /* Close the reader end in the parent */

Это запускает дочерний процесс из процесса оболочки с включенным управлением заданиями.Дочерний процесс создается в фоновом режиме.Оболочка ожидает перевода строки (или EOF), затем убивает дочерний элемент.

Когда родитель умирает - независимо от причины, - он закрывает свой конец канала.Дочерняя оболочка получит EOF из чтения и продолжит завершать фоновый дочерний процесс.

Для полноты картины.На macOS вы можете использовать kqueue:

void noteProcDeath(
    CFFileDescriptorRef fdref, 
    CFOptionFlags callBackTypes, 
    void* info) 
{
    // LOG_DEBUG(@"noteProcDeath... ");

    struct kevent kev;
    int fd = CFFileDescriptorGetNativeDescriptor(fdref);
    kevent(fd, NULL, 0, &kev, 1, NULL);
    // take action on death of process here
    unsigned int dead_pid = (unsigned int)kev.ident;

    CFFileDescriptorInvalidate(fdref);
    CFRelease(fdref); // the CFFileDescriptorRef is no longer of any use in this example

    int our_pid = getpid();
    // when our parent dies we die as well.. 
    LOG_INFO(@"exit! parent process (pid %u) died. no need for us (pid %i) to stick around", dead_pid, our_pid);
    exit(EXIT_SUCCESS);
}


void suicide_if_we_become_a_zombie(int parent_pid) {
    // int parent_pid = getppid();
    // int our_pid = getpid();
    // LOG_ERROR(@"suicide_if_we_become_a_zombie(). parent process (pid %u) that we monitor. our pid %i", parent_pid, our_pid);

    int fd = kqueue();
    struct kevent kev;
    EV_SET(&kev, parent_pid, EVFILT_PROC, EV_ADD|EV_ENABLE, NOTE_EXIT, 0, NULL);
    kevent(fd, &kev, 1, NULL, 0, NULL);
    CFFileDescriptorRef fdref = CFFileDescriptorCreate(kCFAllocatorDefault, fd, true, noteProcDeath, NULL);
    CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack);
    CFRunLoopSourceRef source = CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, fdref, 0);
    CFRunLoopAddSource(CFRunLoopGetMain(), source, kCFRunLoopDefaultMode);
    CFRelease(source);
}

Есть ли у дочернего процесса канал к / от родительского процесса?Если это так, вы получите SIGPIPE при записи или получите EOF при чтении - эти условия могут быть обнаружены.

В Linux вы можете установить родительский сигнал смерти в дочерний, например:

#include <sys/prctl.h> // prctl(), PR_SET_PDEATHSIG
#include <signal.h> // signals
#include <unistd.h> // fork()
#include <stdio.h>  // perror()

// ...

pid_t ppid_before_fork = getpid();
pid_t pid = fork();
if (pid == -1) { perror(0); exit(1); }
if (pid) {
    ; // continue parent execution
} else {
    int r = prctl(PR_SET_PDEATHSIG, SIGTERM);
    if (r == -1) { perror(0); exit(1); }
    // test in case the original parent exited just
    // before the prctl() call
    if (getppid() != ppid_before_fork)
        exit(1);
    // continue child execution ...

Обратите внимание, что сохранение идентификатора родительского процесса до форка и тестирование его в дочернем после prctl() устраняет состояние гонки между prctl() и выход из процесса, который вызвал дочерний элемент.

Также обратите внимание, что сигнал смерти родителя дочернего элемента очищается во вновь созданных собственных дочерних элементах.На него не влияет execve().

Этот тест может быть упрощен, если мы уверены, что системный процесс, отвечающий за принятие всех сироты имеет PID 1:

pid_t pid = fork();
if (pid == -1) { perror(0); exit(1); }
if (pid) {
    ; // continue parent execution
} else {
    int r = prctl(PR_SET_PDEATHSIG, SIGTERM);
    if (r == -1) { perror(0); exit(1); }
    // test in case the original parent exited just
    // before the prctl() call
    if (getppid() == 1)
        exit(1);
    // continue child execution ...

Полагаясь на то, что системный процесс является init и все же наличие PID 1 не является переносимым. POSIX.1-2008 определяет:

Идентификатор родительского процесса всех существующих дочерних процессов и процессов-зомби вызывающего процесса должен быть установлен на идентификатор процесса системного процесса, определенного реализацией.То есть эти процессы должны быть унаследованы специальным системным процессом.

Традиционно системный процесс, усыновляющий всех сирот, имеет PID 1, т. е.init - который является предком всех процессов.

В современных системах, таких как Linux или FreeBSD такую роль мог бы выполнять другой процесс.Например, в Linux процесс может вызывать prctl(PR_SET_CHILD_SUBREAPER, 1) утвердиться в качестве системного процесса, который наследует всех сирот любого из своих потомков (ср.ан пример на Fedora 25).

Вдохновленный другим ответом здесь, я придумал следующее полностью POSIX-решение.Общая идея состоит в том, чтобы создать промежуточный процесс между родительским и дочерним, который имеет одну цель:Обратите внимание, когда родитель умирает, и явно убейте дочернего.

Этот тип решения полезен, когда код в дочернем элементе не может быть изменен.

int p[2];
pipe(p);
pid_t child = fork();
if (child == 0) {
    close(p[1]); // close write end of pipe
    setpgid(0, 0); // prevent ^C in parent from stopping this process
    child = fork();
    if (child == 0) {
        close(p[0]); // close read end of pipe (don't need it here)
        exec(...child process here...);
        exit(1);
    }
    read(p[0], 1); // returns when parent exits for any reason
    kill(child, 9);
    exit(1);
}

У этого метода есть два небольших предостережения:

  • Если вы намеренно убьете промежуточный процесс, то дочерний процесс не будет убит, когда родитель умрет.
  • Если дочерний процесс завершит работу раньше родительского, то промежуточный процесс попытается уничтожить исходный дочерний pid, который теперь может относиться к другому процессу.(Это можно было бы исправить с помощью дополнительного кода в промежуточном процессе.)

Кроме того, фактический код, который я использую, написан на Python.Вот это для полноты картины:

def run(*args):
    (r, w) = os.pipe()
    child = os.fork()
    if child == 0:
        os.close(w)
        os.setpgid(0, 0)
        child = os.fork()
        if child == 0:
            os.close(r)
            os.execl(args[0], *args)
            os._exit(1)
        os.read(r, 1)
        os.kill(child, 9)
        os._exit(1)
    os.close(r)

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

IT является родительский процесс может перехватить большинство возможных событий завершения и попытаться убить дочерний процесс в этот момент, но всегда есть некоторые, которые не могут быть перехвачены.

Например, ни один процесс не может перехватить SIGKILL.Когда ядро обработает этот сигнал, оно завершит указанный процесс без какого-либо уведомления этого процесса.

Продолжая аналогию, единственный другой стандартный способ сделать это - для ребенка совершить самоубийство, когда он обнаруживает, что у него больше нет родителя.

Существует способ сделать это только для Linux с prctl(2) - смотрите другие ответы.

Как указывали другие люди, полагаться на то, что родительский pid становится равным 1 при выходе родительского сервера, непереносимо.Вместо того чтобы ждать определенного идентификатора родительского процесса, просто дождитесь изменения идентификатора:

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

Добавьте режим микроспания по желанию, если вы не хотите проводить опрос на полной скорости.

Этот вариант кажется мне проще, чем использовать канал или полагаться на сигналы.

Установите обработчик ловушек чтобы перехватить SIGINT, который убивает ваш дочерний процесс, если он все еще жив, хотя другие постеры верны, что он не перехватит SIGKILL.

Откройте .файл блокировки с эксклюзивным доступом и проведите дочерний опрос по нему, пытаясь открыть его - если открытие завершится успешно, дочерний процесс должен завершиться

Это решение сработало для меня:

  • Передайте канал stdin дочернему элементу - вам не нужно записывать какие-либо данные в поток.
  • Дочерний элемент читает бесконечно от stdin до EOF.EOF сигнализирует о том, что родитель ушел.
  • Это надежный и переносимый способ определить, когда родитель ушел.Даже если родительский сервер выйдет из строя, операционная система закроет канал.

Это было для процесса рабочего типа, существование которого имело смысл только тогда, когда родительский элемент был жив.

Я думаю, что быстрый и грязный способ - это создать канал между дочерним и родительским.Когда родитель завершит работу, дочерние элементы получат SIGPIPE.

На некоторых плакатах уже упоминались трубы и kqueue.На самом деле вы также можете создать пару соединенных Доменные сокеты Unix по socketpair() звони.Тип розетки должен быть SOCK_STREAM.

Предположим, у вас есть два файловых дескриптора сокета fd1, fd2.Сейчас fork() создать дочерний процесс, который унаследует fds.В родительском вы закрываете fd2, а в дочернем вы закрываете fd1.Теперь каждый процесс может poll() оставшийся открытым fd на своем собственном конце для POLLIN событие.До тех пор, пока каждая сторона явно не close() его fd в течение обычного срока службы, вы можете быть совершенно уверены, что POLLHUP флаг должен указывать на завершение другого участника (независимо от того, чистый он или нет).Получив уведомление об этом событии, ребенок может решить, что делать (напримерумереть).

#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <poll.h>
#include <stdio.h>

int main(int argc, char ** argv)
{
    int sv[2];        /* sv[0] for parent, sv[1] for child */
    socketpair(AF_UNIX, SOCK_STREAM, 0, sv);

    pid_t pid = fork();

    if ( pid > 0 ) {  /* parent */
        close(sv[1]);
        fprintf(stderr, "parent: pid = %d\n", getpid());
        sleep(100);
        exit(0);

    } else {          /* child */
        close(sv[0]);
        fprintf(stderr, "child: pid = %d\n", getpid());

        struct pollfd mon;
        mon.fd = sv[1];
        mon.events = POLLIN;

        poll(&mon, 1, -1);
        if ( mon.revents & POLLHUP )
            fprintf(stderr, "child: parent hung up\n");
        exit(0);
    }
}

Вы можете попробовать скомпилировать приведенный выше концептуальный код и запустить его в терминале следующим образом ./a.out &.У вас есть примерно 100 секунд, чтобы поэкспериментировать с отключением родительского PID различными сигналами, иначе он просто завершит работу.В любом случае, вы должны увидеть сообщение "дочерний:родитель повесил трубку".

По сравнению с методом, использующим SIGPIPE обработчик, этот метод не требует попытки write() звони.

Этот метод также симметричный, т. е.процессы могут использовать один и тот же канал для мониторинга существования друг друга.

Это решение вызывает только функции POSIX.Я пробовал это в Linux и FreeBSD.Я думаю, что это должно работать на других Unix, но я действительно не тестировал.

Смотрите также:

  • unix(7) справочных страниц Linux, unix(4) для FreeBSD, poll(2), socketpair(2), socket(7) в Linux.

Под POSIX ( ПОЛОЖЕНИЕ ), тот exit(), _exit() и _Exit() функции определены для:

  • Если процесс является управляющим процессом, сигнал SIGHUP должен быть отправлен каждому процессу в группе процессов переднего плана управляющего терминала, принадлежащего вызывающему процессу.

Итак, если вы организуете, чтобы родительский процесс был управляющим процессом для своей группы процессов, дочерний процесс должен получать сигнал SIGHUP при выходе родительского процесса.Я не совсем уверен, что это происходит, когда родительский сервер выходит из строя, но я думаю, что это происходит.Конечно, в случаях без сбоев это должно работать нормально.

Обратите внимание, что вам, возможно, придется прочитать довольно много мелкого шрифта, включая раздел "Базовые определения", а также информацию о системных службах для exit() и setsid() и setpgrp() - чтобы получить полную картину.(Я бы тоже так поступил!)

Если вы отправляете сигнал на pid 0, используя, например

kill(0, 2); /* SIGINT */

этот сигнал посылается всей группе процессов, тем самым фактически убивая дочернее устройство.

Вы можете легко протестировать это с помощью чего-то вроде:

(cat && kill 0) | python

Если вы затем нажмете ^D, вы увидите текст "Terminated" как признак того, что интерпретатор Python действительно был убит, а не просто завершен из-за закрытия stdin.

На случай, если это имеет отношение к кому-либо еще, когда я создаю экземпляры JVM в разветвленных дочерних процессах из C ++, единственный способ заставить экземпляры JVM завершиться должным образом после завершения родительского процесса - это выполнить следующее.Надеюсь, кто-нибудь сможет оставить отзыв в комментариях, если это был не лучший способ сделать это.

1) Позвонить prctl(PR_SET_PDEATHSIG, SIGHUP) в разветвленном дочернем процессе, как предлагалось перед запуском Java-приложения через execv, и

2) Добавьте перехват завершения работы в Java-приложение, которое опрашивает до тех пор, пока его родительский PID не будет равен 1, затем выполните жесткую Runtime.getRuntime().halt(0).Опрос выполняется путем запуска отдельной командной строки, которая запускает ps команда (См.: Как мне найти свой PID в Java или JRuby в Linux?).

ПРАВКА 130118:

Похоже, это не было надежным решением.Я все еще немного пытаюсь понять нюансы происходящего, но я все еще иногда получал бесхозные процессы JVM при запуске этих приложений в сеансах screen / SSH.

Вместо опроса PPID в Java-приложении я просто заставил хук выключения выполнить очистку с последующей жесткой остановкой, как описано выше.Затем я позаботился о том, чтобы вызвать waitpid в родительском приложении C ++ на порожденном дочернем процессе, когда пришло время завершить все.Это представляется более надежным решением, поскольку дочерний процесс гарантирует, что он завершится, в то время как родительский использует существующие ссылки, чтобы убедиться, что его дочерние процессы завершатся.Сравните это с предыдущим решением, в котором родительский процесс завершался, когда ему заблагорассудится, и дочерние элементы пытались выяснить, были ли они осиротевшими до завершения.

Если родитель умирает, 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

Я нашел 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 чтобы запустить ваш процесс с подключенным управляющим терминалом.
Когда вы убиваете текущий процесс в любом случае, даже kill -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(.....);
    */

Мне удалось создать портативное решение без опроса с 3 процессами, злоупотребляя управлением терминалом и сеансами.Это ментальная мастурбация, но она работает.

Хитрость в том, что:

  • запущен процесс A
  • процесс A создает канал P (и никогда не считывает из него данные)
  • процесс A разветвляется на процесс B
  • процесс B создает новый сеанс
  • процесс B выделяет виртуальный терминал для этого нового сеанса
  • процесс B устанавливает обработчик SIGCHLD таким образом, чтобы он умирал при выходе дочернего элемента
  • процесс B устанавливает обработчик SIGPIPE
  • процесс B переходит в процесс C
  • процесс C делает все, что ему нужно (напримерexec() использует неизмененный двоичный файл или выполняет любую логику)
  • процесс B записывает в канал P (и блокирует этот путь)
  • процесс A ожидает () s процесса B и завершает работу, когда он умирает

Таким образом:

  • если процесс A умрет:процесс B получает SIGPIPE и умирает
  • если процесс B умрет:функция wait() процесса A возвращается и завершается, процесс C получает SIGHUP (потому что, когда руководитель сеанса сеанса с подключенным терминалом умирает, все процессы в группе процессов переднего плана получают SIGHUP)
  • если процесс C умрет:процесс B получает SIGCHLD и умирает, поэтому процесс A умирает

Недостатки:

  • процесс C не может обработать SIGHUP
  • процесс C будет запущен в другом сеансе
  • процесс C не может использовать API сеанса / группы процессов, потому что это нарушит хрупкую настройку
  • создание терминала для каждой такой операции - не самая лучшая идея на свете

Несмотря на то, что прошло 7 лет, я только что столкнулся с этой проблемой, когда запускал приложение SpringBoot, которому необходимо запустить webpack-dev-server во время разработки и которое необходимо отключить, когда внутренний процесс останавливается.

Я стараюсь использовать Runtime.getRuntime().addShutdownHook но это работало в Windows 10, но не в Windows 7.

Я изменил его, чтобы использовать выделенный поток, который ожидает завершения процесса или для InterruptedException который, кажется, корректно работает в обеих версиях Windows.

private void startWebpackDevServer() {
    String cmd = isWindows() ? "cmd /c gradlew webPackStart" : "gradlew webPackStart";
    logger.info("webpack dev-server " + cmd);

    Thread thread = new Thread(() -> {

        ProcessBuilder pb = new ProcessBuilder(cmd.split(" "));
        pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
        pb.redirectError(ProcessBuilder.Redirect.INHERIT);
        pb.directory(new File("."));

        Process process = null;
        try {
            // Start the node process
            process = pb.start();

            // Wait for the node process to quit (blocking)
            process.waitFor();

            // Ensure the node process is killed
            process.destroyForcibly();
            System.setProperty(WEBPACK_SERVER_PROPERTY, "true");
        } catch (InterruptedException | IOException e) {
            // Ensure the node process is killed.
            // InterruptedException is thrown when the main process exit.
            logger.info("killing webpack dev-server", e);
            if (process != null) {
                process.destroyForcibly();
            }
        }

    });

    thread.start();
}

Исторически, начиная с UNIX версии 7, система процессов обнаруживала бесхозность процессов путем проверки родительского идентификатора процесса.Как я уже сказал, исторически сложилось так, что init(8) системный процесс - это особый процесс только по одной причине:Оно не может умереть.Он не может умереть, потому что алгоритм ядра, обрабатывающий присвоение нового идентификатора родительского процесса, зависит от этого факта.когда процесс выполняет свою exit(2) вызов (посредством системного вызова процесса или внешней задачи, посылающей ему сигнал или т.п.) ядро переназначает всем дочерним элементам этого процесса идентификатор процесса инициализации в качестве идентификатора их родительского процесса.Это приводит к самому простому тестированию и наиболее переносимому способу узнать, стал ли процесс бесхозным.Просто проверьте результат getppid(2) системный вызов, и если это идентификатор процесса init(2) затем процесс стал бесхозным перед системным вызовом.

Из этого подхода вытекают две проблемы, которые могут привести к проблемам:

  • во-первых, у нас есть возможность изменить init процесс для любого пользовательского процесса, так как же мы можем гарантировать, что процесс инициализации всегда будет родительским для всех сиротских процессов?Ну, в exit код системного вызова существует явная проверка, чтобы увидеть, является ли процесс, выполняющий вызов, процессом инициализации (процессом с pid, равным 1), и если это так, ядро впадает в панику (оно больше не должно иметь возможности поддерживать иерархию процессов), поэтому процессу инициализации не разрешается выполнять exit(2) звони.
  • во-вторых, в базовом тесте, представленном выше, есть условие гонки.Идентификатор процесса инициализации исторически считается равным 1, но это не гарантируется подходом POSIX, который гласит (как указано в другом ответе), что для этой цели зарезервирован только системный идентификатор процесса.Почти ни одна реализация posix не делает этого, и вы можете предположить в оригинальных системах, производных от unix, что, имея 1 как ответ на getppid(2) системного вызова достаточно, чтобы предположить, что процесс является бесхозным.Другой способ проверить - это сделать getppid(2) сразу после разветвления и сравните это значение с результатом нового вызова.Это просто работает не во всех случаях, поскольку оба вызова не являются атомарными вместе, и родительский процесс может завершиться после fork(2) и перед первым getppid(2) системный вызов.Процессparent id only changes once, when its parent does anвыход (2)call, so this should be enough to check if theполучить идентификатор (2)result changed between calls to see that parent process has exit. This test is not valid for the actual children of the init process, because they are always children ofinit(8)`, но вы можете смело предположить, что эти процессы также не имеют родительского элемента (за исключением случаев, когда вы заменяете в системе процесс init)

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

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

Видишь клон (2), пространства имен pid(7), и неразделенный (2).

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top