Магия с PID процессов

Имеется несколько скриптов (в моем случае, t и t1). Имеется программа, запускающая эти скрипты и выводящая их PID-ы (В дальнейшем планируется использовать пиды для автоматического завершения):

#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <string>

// Функция запуска программы и возврата её PID
pid_t run_async(const char *cmd) {
    pid_t child_pid = fork();

    if (child_pid == -1) {
        perror("Fork failed");
        exit(EXIT_FAILURE);
    }

    if (child_pid == 0) {
        execl("/bin/bash", "bash", "-c", cmd, NULL);
        perror("Execl failed");
        _exit(EXIT_FAILURE);
    }

    return child_pid;
}

//-------------------------------------------------------
int main(){
  std::cout << run_async("./bin/t &") << std::endl;
  std::cout << run_async("./bin/t1 &") << std::endl;

  return 0;
}

Проблема в том, что PID выводятся неправильно. В моем случае пид меньше реального на 2 (реальные пиды процессов я посмотрел командой ps -A). Подскажите, с чем это связано и каким образом это можно исправить?


Ответы (2 шт):

Автор решения: Solt
  1. Предположим, у вашей программы при запуске будет PID 1
  2. При форке мы получаем дочерний процесс с PID 2
  3. Форкнутый процесс заменяет себя на баш с PID 2
  4. Баш запускает ваш скрипт t с PID 3
  5. Второй форк создаёт дочерний PID 4
  6. В нем заменяемся баш с PID 4
  7. А дальше скрипт t1 с PID 5

Конечно, цифры могут не идти друг за другом.

Так что их целых 5 штук. Который из них вы успели увидеть через ps трудно сказать, но очевидно, что тут есть чему отличаться и на 2, и на 3 и на сколько угодно )

Больше того, у вас команда в виде /bin/bash bash -c ./bin/t & Выглядит как-то странно, возможно тут ещё один промежуточный баш, тогда их даже 7.

Ну и всё-таки немного путает этот механизм. Дочерний процесс подменяется на баш, запущенный в фон с '&'. Форкнутый процесс уже в фоне, зачем из него запускать баш в фон, сам же он при этом закончит свою работу.

Нейронка (хоть их и не любят) даже нарисовала мне схемку:

1. main (родительский)
   ├── 2. child1 (bash -c "./bin/t &")
   │    └── 3. ./bin/t (фоновый процесс)
   └── 4. child2 (bash -c "./bin/t1 &")
        └── 5. ./bin/t1 (фоновый процесс)
→ Ссылка
Автор решения: Serge3leo

В комментариях сразу не сообразил, точным функциональным аналогом вашего кода будет:

// Функция запуска программы и возврата её PID
pid_t run_async(const char *cmd) {
    pid_t child_pid = fork();

    if (child_pid == -1) {
        perror("Fork failed");
        exit(EXIT_FAILURE);
    }

    if (child_pid == 0) {
        execlp(cmd, cmd, NULL);
        perror("Execl failed");
        _exit(EXIT_FAILURE);
    }

    return child_pid;
}

//-------------------------------------------------------
int main(){
  std::cout << run_async("./bin/t") << std::endl;
  std::cout << run_async("./bin/t1") << std::endl;

  return 0;
}

Если "./bin/t" или "./bin/t1" исполняемые файлы скриптов начинающиеся строкой "#!", то для них будет вызван стандартный интерпретатор (точно так же, как и вашем коде). При необходимости, для башизмов, можно использовать "#!/usr/bin/env bash".

Однако, ввиду отсутствия оператора шелл "&", номера процессов станут корректными.

→ Ссылка