C 杀死以popen启动的进程

C 杀死以popen启动的进程,c,multithreading,kill,popen,C,Multithreading,Kill,Popen,使用popen打开进程的管道后,是否有方法终止已启动的进程?(使用pclose不是我想要的,因为这将等待进程完成,但我需要终止它。)显而易见的方法是系统(“pkill进程名称”) 显然,如果有多个进程实例在运行,这是有问题的。popen实际上并不启动线程,而是分叉进程。当我查看定义时,似乎没有一种简单的方法可以获取该进程的PID并杀死它。可能有一些困难的方法,比如检查进程树,但我想最好使用pipe、fork和exec函数来模拟popen的行为。然后,您可以使用从fork()获得的PID来终止子进

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

显而易见的方法是系统(“pkill进程名称”)


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

popen实际上并不启动线程,而是分叉进程。当我查看定义时,似乎没有一种简单的方法可以获取该进程的PID并杀死它。可能有一些困难的方法,比如检查进程树,但我想最好使用pipe、fork和exec函数来模拟popen的行为。然后,您可以使用从fork()获得的PID来终止子进程。

不要使用
popen()
,编写您自己的包装器,以满足您的需要

使用
fork()
,然后替换
stdin
&
stdout
使用
dup2()
,然后对您的孩子调用
exec()

这样,您的家长将拥有确切的子PID,您可以使用
kill()

谷歌搜索“popen2()实现”中的一些示例代码 如何实现
popen()
正在做的事情。只有十几行 长的从中我们可以看到 下面是一个类似的示例:

#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;
}
#定义读取0
#定义写入1
皮杜
popen2(常量字符*命令,int*infp,int*outpp)
{
int p_stdin[2],p_stdout[2];
pid_t pid;
如果(管道(压力标准差)!=0 |管道(压力标准差)!=0)
返回-1;
pid=fork();
if(pid<0)
返回pid;
否则如果(pid==0)
{
关闭(p_stdin[WRITE]);
dup2(p_stdin[READ],READ);
关闭(p_stdout[READ]);
dup2(p_stdout[WRITE],WRITE);
execl(“/bin/sh”、“sh”、“-c”,命令,空);
perror(“execl”);
出口(1);
}
if(infp==NULL)
关闭(p_stdin[WRITE]);
其他的
*infp=p_stdin[写入];
if(outpp==NULL)
关闭(p_stdout[READ]);
其他的
*outpp=p_stdout[READ];
返回pid;
}

注意:看起来popen2()是您想要的,但是我的发行版似乎没有这个方法

事实上,如果进程正在进行I/O(应该是这样,否则为什么
popen
而不是
system
(3)?),那么
pclose
应该在下次尝试读取或写入时用
SIGPIPE
对其进行打击,并且应该很好地结束:-)

我在python中做了类似的事情,在这里,您可以杀死一个子流程以及为此而派生的任何子流程。这实际上与slacy的解类似。
这是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;
}

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

这可以通过在父进程上添加关闭未使用的管道来解决

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);
}
#定义读取0
#定义写入1
皮杜
popen2(常量字符*命令,int*infp,int*outpp)
{
int p_stdin[2],p_stdout[2];
pid_t pid;
如果(管道(压力标准差)!=0 |管道(压力标准差)!=0)
返回-1;
pid=fork();
if(pid<0)
返回pid;
否则如果(pid==0)
{
dup2(p_stdin[READ],stdin_FILENO);
dup2(p_stdout[WRITE],stdout_FILENO);
//关闭子进程上的未使用描述符。
关闭(p_stdin[READ]);
关闭(p_stdin[WRITE]);
关闭(p_stdout[READ]);
关闭(p_stdout[WRITE]);
//可以更改为任何exec*函数族。
execl(“/bin/bash”、“bash”、“-c”,命令,NULL);
perror(“execl”);
出口(1);
}
//关闭父进程上未使用的描述符。
关闭(p_stdin[READ]);
关闭(p_stdout[WRITE]);
if(infp==NULL)
关闭(p_stdin[WRITE]);
其他的
*infp=p_stdin[写入];
if(outpp==NULL)
关闭(p_stdout[READ]);
其他的
*outpp=p_stdout[READ];
返回pid;
}
int
pclose2(pid\u t pid){
国际内部统计;
waitpid(pid和内部统计,0);
返回WEXITSTATUS(内部统计);
}
我只是在(bash)脚本的第一行:

echo PID $$
然后我读取pid,并使用它执行以下操作:
kill(pid,9)

这种情况下,多个实例正在运行,需要针对一个精确的实例。这并不能解决fork的内存复制问题。我们可能不想为此打电话给forkreason@phooji蟒蛇和什么有什么关系?@MahmoudAl Qudsi:哎呀。我一定是想问太多python问题了。[前面与python相关的评论编辑]上面需要“close(p_stdin[READ]);close(p_stdout[WRITE]),以避免两个不需要的打开文件描述符延迟(这会阻止诸如fgets()之类的调用检测到分叉子级已退出)。这个答案中的代码有一个严重问题:如果
execl(),它将调用
exit()
if
execl()
失败。这将导致调用父进程注册的任何出口处理程序,并将从父进程复制的缓冲流数据刷新到父进程拥有的流。如果C++程序调用了<代码> PONEN2()/Cux>函数,也将调用父进程复制的静态析构函数。代码应该调用
\u exit()
而不是
exit()
,以绕过父进程的
ex
echo PID $$