终止使用popen启动的进程

时间:2022-08-26 20:24:54

After opening a pipe to a process with popen, is there a way to kill the process that has been started? (Using pclose is not what I want because that will wait for the process to finish, but I need to kill it.)

在打开一个与popen的进程的管道之后,是否有一种方法可以杀死已经启动的进程?(使用pclose不是我想要的,因为这将等待进程完成,但我需要终止它。)

8 个解决方案

#1


25  

Don't use popen(), and write your own wrapper that does what you'd like.

不要使用popen(),并且编写自己的包装器来做你想做的事情。

It's fairly straightforward to fork(), and then replace stdin & stdout by using dup2(), and then calling exec() on your child.

fork()非常简单,然后使用dup2()替换stdin和stdout,然后在您的孩子上调用exec()。

That way, your parent will have the exact child PID, and you can use kill() on that.

这样,您的父类就会有确切的子PID,并且您可以在它上使用kill()。

Google search for "popen2() implementation" for some sample code on how to implement what popen() is doing. It's only a dozen or so lines long. Taken from dzone.com we can see an example that looks like this:

谷歌搜索“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: Seems like popen2() is what you want, but my distribution doesn't seem to come with this method.

NB:似乎popen2()是您想要的,但是我的发行版似乎没有采用这种方法。

#2


5  

Here is an improved version of popen2 (credit is due to Sergey L.). The version posted by slacy does not return the PID of the process created in popen2, but the PID assigned to sh.

这里有一个改进版的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;
}

The new version is to be called with

新版本将被调用

char *command[] = {"program", "arg1", "arg2", ..., NULL};

#3


4  

popen does not actually start a thread, but rather forks a process. As I look at the definition, it doesn't look like there is an easy way to get PID of that process and kill it. There might be difficult ways like examining process tree, but i guess you'd be better off with using pipe, fork and exec functions to mimic behaviour of popen. Then you can use PID you get from fork() to kill the child process.

popen实际上并不启动线程,而是派生进程。当我看定义的时候,看起来并没有一种简单的方法来获取这个过程的PID并将其扼杀。可能有一些困难的方法,比如检查进程树,但是我认为最好使用管道、fork和exec函数来模拟popen的行为。然后可以使用从fork()获得的PID来杀死子进程。

#4


3  

Actually if the process is doing I/O (which it should be, otherwise why popen instead of system(3)?), then pclose should whack it with a SIGPIPE the next time it tries to read or write, and it should fall over nicely :-)

实际上,如果进程正在执行I/O(应该是I/O,否则为什么要使用popen而不是system(3))?

#5


0  

The obvious way is system("pkill process_name");

最明显的方法是系统(“pkill process_name”);

Clearly this is problematic if you have more than one instance of the process running.

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

#6


0  

I did something similar in python, where you could kill a subprocess and any subprocesses forked for that. It's similar to slacy's solution actually. http://www.pixelbeat.org/libs/subProcess.py

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

#7


0  

I have follow idea of @slacy that create function popen2.
But found problem when child process is die, parent process that still read file descripter outfp not return from function.

我已经遵循了创建函数popen2的@slacy的想法。但发现子进程死时,仍然读取文件描述符输出的父进程不返回函数。

That could fix by add close unuse pipe on parent process.

这可以通过在父进程中添加关闭的未使用管道来修复。

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

We can get correct pid of new process by using bash as shell.

利用bash作为shell,可以得到新进程的正确pid。

execl("/bin/bash", "bash", "-c", command, NULL);

When child process die the caller of function popen2 should collect status of child process by call pclose2. if we don't collect that status child process could be zombie process when it terminate.

当子进程死时,函数popen2的调用者应该通过调用pclose2来收集子进程的状态。如果我们不收集这个状态子进程,当它终止时可能是僵尸进程。

This is the full code that tested and work as expect.

这是测试过的完整代码,并按照预期运行。

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

#8


0  

I simply put in the (bash) script, in the first line:

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

echo PID $$

then I read the pid, and use it to do a : kill(pid,9)

然后我读了pid,用它来做:kill(pid,9)

#1


25  

Don't use popen(), and write your own wrapper that does what you'd like.

不要使用popen(),并且编写自己的包装器来做你想做的事情。

It's fairly straightforward to fork(), and then replace stdin & stdout by using dup2(), and then calling exec() on your child.

fork()非常简单,然后使用dup2()替换stdin和stdout,然后在您的孩子上调用exec()。

That way, your parent will have the exact child PID, and you can use kill() on that.

这样,您的父类就会有确切的子PID,并且您可以在它上使用kill()。

Google search for "popen2() implementation" for some sample code on how to implement what popen() is doing. It's only a dozen or so lines long. Taken from dzone.com we can see an example that looks like this:

谷歌搜索“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: Seems like popen2() is what you want, but my distribution doesn't seem to come with this method.

NB:似乎popen2()是您想要的,但是我的发行版似乎没有采用这种方法。

#2


5  

Here is an improved version of popen2 (credit is due to Sergey L.). The version posted by slacy does not return the PID of the process created in popen2, but the PID assigned to sh.

这里有一个改进版的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;
}

The new version is to be called with

新版本将被调用

char *command[] = {"program", "arg1", "arg2", ..., NULL};

#3


4  

popen does not actually start a thread, but rather forks a process. As I look at the definition, it doesn't look like there is an easy way to get PID of that process and kill it. There might be difficult ways like examining process tree, but i guess you'd be better off with using pipe, fork and exec functions to mimic behaviour of popen. Then you can use PID you get from fork() to kill the child process.

popen实际上并不启动线程,而是派生进程。当我看定义的时候,看起来并没有一种简单的方法来获取这个过程的PID并将其扼杀。可能有一些困难的方法,比如检查进程树,但是我认为最好使用管道、fork和exec函数来模拟popen的行为。然后可以使用从fork()获得的PID来杀死子进程。

#4


3  

Actually if the process is doing I/O (which it should be, otherwise why popen instead of system(3)?), then pclose should whack it with a SIGPIPE the next time it tries to read or write, and it should fall over nicely :-)

实际上,如果进程正在执行I/O(应该是I/O,否则为什么要使用popen而不是system(3))?

#5


0  

The obvious way is system("pkill process_name");

最明显的方法是系统(“pkill process_name”);

Clearly this is problematic if you have more than one instance of the process running.

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

#6


0  

I did something similar in python, where you could kill a subprocess and any subprocesses forked for that. It's similar to slacy's solution actually. http://www.pixelbeat.org/libs/subProcess.py

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

#7


0  

I have follow idea of @slacy that create function popen2.
But found problem when child process is die, parent process that still read file descripter outfp not return from function.

我已经遵循了创建函数popen2的@slacy的想法。但发现子进程死时,仍然读取文件描述符输出的父进程不返回函数。

That could fix by add close unuse pipe on parent process.

这可以通过在父进程中添加关闭的未使用管道来修复。

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

We can get correct pid of new process by using bash as shell.

利用bash作为shell,可以得到新进程的正确pid。

execl("/bin/bash", "bash", "-c", command, NULL);

When child process die the caller of function popen2 should collect status of child process by call pclose2. if we don't collect that status child process could be zombie process when it terminate.

当子进程死时,函数popen2的调用者应该通过调用pclose2来收集子进程的状态。如果我们不收集这个状态子进程,当它终止时可能是僵尸进程。

This is the full code that tested and work as expect.

这是测试过的完整代码,并按照预期运行。

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

#8


0  

I simply put in the (bash) script, in the first line:

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

echo PID $$

then I read the pid, and use it to do a : kill(pid,9)

然后我读了pid,用它来做:kill(pid,9)