杀死一个以popen开始的进程

时间:2009-02-13 23:16:18

标签: c multithreading kill popen

打开管道到popen的进程后,是否有办法终止已启动的进程? (使用pclose不是我想要的,因为它会等待进程完成,但我需要杀死它。)

8 个答案:

答案 0 :(得分:26)

不要使用popen(),并编写自己喜欢的包装器。

fork()相当简单,然后替换stdin&标准输出 通过使用dup2(),然后在您的孩子上调用exec()。

这样,您的父母将拥有确切的子PID,您可以使用 杀死()。

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;
}

注意:似乎popen2()就像你想要的那样,但我的发行版似乎没有这种方法。

答案 1 :(得分:5)

这是popen2的改进版本(信用归功于Sergey L.)。 slacy发布的版本不会返回在popen2中创建的进程的PID,而是返回分配给sh的PID。

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};

答案 2 :(得分:4)

popen实际上并不启动一个线程,而是分叉一个进程。当我看到定义时,看起来并不像是有一种简单的方法可以获得该进程的PID并将其终止。可能有一些困难的方法,比如检查进程树,但我猜你最好使用pipe,fork和exec函数来模仿popen的行为。然后你可以使用从fork()获得的PID来杀死子进程。

答案 3 :(得分:3)

实际上,如果流程正在进行I / O(应该是I / O,否则为什么popen而不是system(3)?),那么pclose应该使用{ {1}}下次尝试读取或写入时,它应该很好地解决: - )

答案 4 :(得分:0)

显而易见的方法是system(“pkill process_name”);

如果您有多个进程实例正在运行,显然这是有问题的。

答案 5 :(得分:0)

我在python中做了类似的事情,在那里你可以杀死一个子进程和任何分叉的子进程。它实际上与slacy的解决方案类似。 http://www.pixelbeat.org/libs/subProcess.py

答案 6 :(得分:0)

我遵循创建函数popen2的@slacy的想法 但是当子进程死亡时发现问题,仍然读取文件描述符outfp的父进程不从函数返回。

这可以通过在父进程上添加关闭unuse管道来解决。

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

我们可以使用bash作为shell来获得正确的新进程pid。

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);
}

答案 7 :(得分:0)

我只是在第一行输入(bash)脚本:

echo PID $$

然后我读了pid,并用它来做: 杀(PID,9)