Подтвердить что ты не робот

Убить процесс, запущенный с помощью popen

После открытия трубы в процессе с popen существует ли способ убить процесс, который был запущен? (Использование pclose - это не то, что я хочу, потому что это будет ждать завершения процесса, но мне нужно его убить.)

4b9b3361

Ответ 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)