После открытия трубы в процессе с popen
существует ли способ убить процесс, который был запущен? (Использование pclose
- это не то, что я хочу, потому что это будет ждать завершения процесса, но мне нужно его убить.)
Убить процесс, запущенный с помощью popen
Ответ 1
Не используйте popen()
, напишите свою собственную обертку, которая делает то, что вы хотите.
Это довольно просто для fork()
, а затем заменить stdin
& stdout
с помощью dup2()
, а затем позвоните exec()
своему ребенку.
Таким образом, ваш родитель будет иметь точный идентификатор ребенка, и вы можете использовать
kill()
об этом.
Поиск Google для "реализации popen2()" для некоторого примера кода на
как реализовать то, что делает popen()
. Это всего десяток или около того строк
долго. Взято с dzone.com мы можем видеть
пример, который выглядит так:
#define READ 0
#define WRITE 1
pid_t
popen2(const char *command, int *infp, int *outfp)
{
int p_stdin[2], p_stdout[2];
pid_t pid;
if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0)
return -1;
pid = fork();
if (pid < 0)
return pid;
else if (pid == 0)
{
close(p_stdin[WRITE]);
dup2(p_stdin[READ], READ);
close(p_stdout[READ]);
dup2(p_stdout[WRITE], WRITE);
execl("/bin/sh", "sh", "-c", command, NULL);
perror("execl");
exit(1);
}
if (infp == NULL)
close(p_stdin[WRITE]);
else
*infp = p_stdin[WRITE];
if (outfp == NULL)
close(p_stdout[READ]);
else
*outfp = p_stdout[READ];
return pid;
}
NB. Похоже, что popen2() - это то, что вам нужно, но мой дистрибутив, похоже, не идет с этим методом.
Ответ 2
Вот улучшенная версия popen2 (кредит принадлежит Сергею Л.). Версия, отправленная slacy, не возвращает PID процесса, созданного в popen2, но PID назначен sh
.
pid_t popen2(const char **command, int *infp, int *outfp)
{
int p_stdin[2], p_stdout[2];
pid_t pid;
if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0)
return -1;
pid = fork();
if (pid < 0)
return pid;
else if (pid == 0)
{
close(p_stdin[WRITE]);
dup2(p_stdin[READ], READ);
close(p_stdout[READ]);
dup2(p_stdout[WRITE], WRITE);
execvp(*command, command);
perror("execvp");
exit(1);
}
if (infp == NULL)
close(p_stdin[WRITE]);
else
*infp = p_stdin[WRITE];
if (outfp == NULL)
close(p_stdout[READ]);
else
*outfp = p_stdout[READ];
return pid;
}
Новая версия должна быть вызвана с помощью
char *command[] = {"program", "arg1", "arg2", ..., NULL};
Ответ 3
popen фактически не запускает поток, а скорее вилки процесса. Поскольку я смотрю на определение, это не похоже, что есть простой способ получить PID этого процесса и убить его. Могут быть сложные способы изучения дерева процессов, но я думаю, вам будет лучше использовать функции pipe, fork и exec для имитации поведения popen. Затем вы можете использовать PID, который вы получаете из fork(), чтобы убить дочерний процесс.
Ответ 4
На самом деле, если процесс выполняет I/O (каким он должен быть, иначе почему popen
вместо system
(3)?), тогда pclose
должен ударить его с помощью SIGPIPE
в следующий раз пытается читать или писать, и он должен хорошо падать: -)
Ответ 5
У меня есть идея @slacy, которая создает функцию popen2.
Но найденная проблема, когда дочерний процесс умирает, родительский процесс, который все еще читает дескриптор файла outfp
, не возвращает из функции.
Это можно исправить, добавив тесный трубок unuse в родительский процесс.
close(p_stdin[READ]);
close(p_stdout[WRITE]);
Мы можем получить правильный pid нового процесса, используя bash как оболочку.
execl("/bin/bash", "bash", "-c", command, NULL);
Когда дочерний процесс умирает, вызывающая функция popen2
должна собирать статус дочернего процесса по вызову pclose2
. если мы не собираем этот статус, дочерний процесс может быть процессом зомби, когда он заканчивается.
Это полный код, который тестировался и работает как ожидаемый.
#define READ 0
#define WRITE 1
pid_t
popen2(const char *command, int *infp, int *outfp)
{
int p_stdin[2], p_stdout[2];
pid_t pid;
if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0)
return -1;
pid = fork();
if (pid < 0)
return pid;
else if (pid == 0)
{
dup2(p_stdin[READ], STDIN_FILENO);
dup2(p_stdout[WRITE], STDOUT_FILENO);
//close unuse descriptors on child process.
close(p_stdin[READ]);
close(p_stdin[WRITE]);
close(p_stdout[READ]);
close(p_stdout[WRITE]);
//can change to any exec* function family.
execl("/bin/bash", "bash", "-c", command, NULL);
perror("execl");
exit(1);
}
// close unused descriptors on parent process.
close(p_stdin[READ]);
close(p_stdout[WRITE]);
if (infp == NULL)
close(p_stdin[WRITE]);
else
*infp = p_stdin[WRITE];
if (outfp == NULL)
close(p_stdout[READ]);
else
*outfp = p_stdout[READ];
return pid;
}
int
pclose2(pid_t pid) {
int internal_stat;
waitpid(pid, &internal_stat, 0);
return WEXITSTATUS(internal_stat);
}
Ответ 6
Очевидным способом является система ( "pkill process_name" );
Очевидно, что это проблематично, если у вас есть несколько экземпляров процесса.
Ответ 7
Я сделал что-то подобное в python, где вы могли убить подпроцесс и любые подпроцессы, раздвоенные для этого. На самом деле это похоже на slacy solution. http://www.pixelbeat.org/libs/subProcess.py
Ответ 8
Я просто положил (bash) script в первую строку:
echo PID $$
то я прочитал pid и использую его для выполнения: убить (PID, 9)