Магия с 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 шт):
- Предположим, у вашей программы при запуске будет PID 1
- При форке мы получаем дочерний процесс с PID 2
- Форкнутый процесс заменяет себя на баш с PID 2
- Баш запускает ваш скрипт t с PID 3
- Второй форк создаёт дочерний PID 4
- В нем заменяемся баш с PID 4
- А дальше скрипт 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 (фоновый процесс)
В комментариях сразу не сообразил, точным функциональным аналогом вашего кода будет:
// Функция запуска программы и возврата её 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".
Однако, ввиду отсутствия оператора шелл "&", номера процессов станут корректными.