Вопрос

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

Это было полезно?

Решение

Не используйте Popen () и пишите свою собственную обертку, которая делает то, что вы хотели бы.

Это довольно просто для fork (), а затем заменить stdin & stdout, используя dup2 (), а затем вызов exec () на вашего ребенка.

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

Google Search для реализации «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 () - это то, что вы хотите, но мое распространение, похоже, не связано с этим методом.

Другие советы

Вот улучшенная версия 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};

Попен на самом деле не запускает нить, а скорее разбивает процесс. Когда я смотрю на определение, не похоже, что существует простой способ получить пид этого процесса и убить его. Там могут быть сложные способы, такие как изучение дерева процессов, но я думаю, вам было бы лучше с использованием функций трубы, вилки и EXEC, чтобы имитировать поведение Попа. Затем вы можете использовать PID, который вы получаете от Fork (), чтобы убить дочерний процесс.

На самом деле, если процесс делает ввод/вывод (что это должно быть, иначе, почему popen вместо system(3)?), Тогда pclose должен ударить его SIGPIPE В следующий раз, когда он пытается читать или написать, и это должно хорошо падать :-)

Я следил за идеей @Slacy, которая создает функцию Popen2.
Но обнаружил проблему, когда дочерний процесс умирает, родительский процесс, который все еще читает дескриптор файлов outfp не возвращать от функции.

Это может исправить путем добавления Close Unlise Tipe в родительский процесс.

close(p_stdin[READ]);
close(p_stdout[WRITE]);

Мы можем получить правильный пид нового процесса, используя 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);
}

Очевидным способом является System ("pkill Process_name");

Очевидно, что это проблематично, если у вас есть более одного экземпляра запуска процесса.

Я сделал что -то подобное в Python, где вы могли бы убить подпроцесс и любые подпроцессы, разветвленные для этого. На самом деле это похоже на решение Slacy.http://www.pixelbeat.org/libs/subprocess.py

Я просто вставлю в сценарий (Bash) в первой строке:

echo PID $$

Затем я читаю PID и использую его, чтобы сделать: kill (pid, 9)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top