Как ждать выхода недетских процессов - PullRequest
29 голосов
/ 21 июля 2009

Для дочерних процессов функции wait() и waitpid() могут использоваться для приостановки выполнения текущего процесса до выхода из дочернего процесса. Но эту функцию нельзя использовать для не дочерних процессов.

Есть ли другая функция, которая может ожидать выхода из любого процесса?

Ответы [ 8 ]

26 голосов
/ 21 июля 2009

Ничто не эквивалентно wait(). Обычной практикой является опрос с использованием kill(pid, 0) и поиск возвращаемого значения -1 и errno из ESRCH, чтобы указать, что процесс завершен.

13 голосов
/ 20 сентября 2011

На BSD и OS X вы можете использовать kqueue с EVFILT_PROC + NOTE_EXIT, чтобы сделать именно это. Опрос не требуется. К сожалению, нет эквивалента Linux.

9 голосов
/ 03 ноября 2014

До сих пор я нашел три способа сделать это в Linux:

  • Опрос: вы проверяете существование процесса очень часто, либо используя kill, либо проверяя наличие /proc/$pid, как в большинстве других ответов
  • Используйте системный вызов ptrace для подключения к процессу, как отладчик, чтобы вы получали уведомление при его выходе, как в ответе a3nm
  • Используйте интерфейс netlink для прослушивания сообщений PROC_EVENT_EXIT - таким образом, ядро ​​сообщает вашей программе каждый раз, когда завершается процесс, и вы просто ждете правильный идентификатор процесса. Я видел только это, описанное в одном месте в Интернете .

Бесстыдный плагин: я работаю над программой (конечно, с открытым исходным кодом; GPLv2), которая выполняет любое из трех.

5 голосов
/ 21 июля 2009

Вы также можете создать сокет или FIFO и читать их. FIFO особенно прост: соедините стандартный вывод вашего ребенка с FIFO и прочитайте. Чтение будет блокироваться до тех пор, пока ребенок не выйдет (по какой-либо причине) или пока не выдаст некоторые данные. Поэтому вам понадобится небольшой цикл для удаления нежелательных текстовых данных.

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

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

3 голосов
/ 26 августа 2011

Вы можете присоединиться к процессу с помощью ptrace(2). Из оболочки strace -p PID >/dev/null 2>&1 вроде бы работает. Это позволит избежать ожидания «занято», хотя это замедлит отслеживаемый процесс и не будет работать на всех процессах (только на вашем, что немного лучше, чем только на дочерних процессах).

2 голосов
/ 21 июля 2009

Ни о чем я не знаю. Помимо решения хаоса, вы можете использовать семафоры, если вы можете изменить программу, которую вы хотите ждать.

Библиотечные функции: sem_open(3), sem_init(3), sem_wait(3), ...

sem_wait(3) выполняет ожидание, так что вам не нужно заниматься занятым ожиданием, как в решении хаоса. Конечно, использование семафоров делает ваши программы более сложными, и это может не стоить проблем.

1 голос
/ 19 февраля 2019

Вот способ подождать, пока любой процесс (не обязательно дочерний) в linux завершится (или погибнет) без опроса:

Использование inotify для ожидания удаления / proc'pid было бы идеальным решением, но, к сожалению, inotify не работает с псевдофайловыми системами, такими как / proc. Однако мы можем использовать его с исполняемым файлом процесса. Пока этот процесс существует, этот файл остается открытым. Таким образом, мы можем использовать inotify с IN_CLOSE_NOWRITE для блокировки до тех пор, пока файл не будет закрыт. Конечно, его можно закрыть по другим причинам (например, если другой процесс с тем же исполняемым файлом завершается), поэтому мы должны отфильтровать эти события другими способами.

Мы можем использовать kill (pid, 0), но это не может гарантировать, что это все тот же процесс. Если мы действительно параноики по этому поводу, мы можем сделать что-то еще.

Вот способ, который должен быть на 100% безопасен от повторного использования pid: мы открываем псевдо-каталог / proc / 'pid' и сохраняем его открытым, пока мы не закончим. Если тем временем создается новый процесс с тем же идентификатором pid, дескриптор файла каталога, который мы храним, все равно будет ссылаться на исходный (или станет недействительным, если старый процесс прекратит существовать), но НИКОГДА не будет ссылаться на новый процесс с повторно использованный пид. Затем мы можем проверить, существует ли исходный процесс, проверяя, например, существует ли файл «cmdline» в каталоге с помощью openat (). Когда процесс завершается или уничтожается, эти псевдофайлы также перестают существовать, поэтому openat () завершится с ошибкой.

вот пример кода:

// return -1 on error, or 0 if everything went well
int wait_for_pid(int pid)
{
    char path[32];
    int in_fd = inotify_init();
    sprintf(path, "/proc/%i/exe", pid);
    if (inotify_add_watch(in_fd, path, IN_CLOSE_NOWRITE) < 0) {
        close(in_fd);
        return -1;
    }
    sprintf(path, "/proc/%i", pid);
    int dir_fd = open(path, 0);
    if (dir_fd < 0) {
        close(in_fd);
        return -1;
    }

    int res = 0;
    while (1) {
        struct inotify_event event;
        if (read(in_fd, &event, sizeof(event)) < 0) {
            res = -1;
            break;
        }
        int f = openat(dir_fd, "fd", 0);
        if (f < 0) break;
        close(f);
    }

    close(dir_fd);
    close(in_fd);
    return res;
}
1 голос
/ 03 августа 2010

Может быть, можно дождаться исчезновения / proc / [pid] или / proc / [pid] / [что-то]?

Существуют функции poll () и другие функции ожидания файловых событий, может быть, это может помочь?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...