题
在打开管道以进行处理之后 popen
, ,有没有办法杀死已经开始的过程? (使用 pclose
不是我想要的,因为那将等待该过程完成,但我需要杀死它。)
解决方案
不要使用popen(),然后写自己的包装器,可以做您想要的。
它对fork()非常简单,然后使用dup2()替换stdin&stdout,然后在孩子上调用exec()。
这样,您的父母将拥有确切的孩子PID,您可以在此使用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(),但是我的分布似乎并不是这种方法。
其他提示
这是Popen2的改进版本(信用归功于Sergey L.)。 Slacy发布的版本不会返回Popen2中创建的过程的PID,而是分配给的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};
Popen实际上并没有启动线程,而是叉一个过程。当我看一下定义时,看起来似乎没有一种简单的方法来获取该过程并杀死它。可能会有一些困难的方法,例如检查过程树,但是我想您最好使用管道,叉子和执行功能来模仿Popen的行为。然后,您可以使用从叉()获得的PID来杀死孩子的过程。
实际上,如果该过程正在执行I/O(应该是这样,否则为什么 popen
代替 system
(3)?),然后 pclose
应该用一个 SIGPIPE
下次尝试阅读或写作时,应该很好地掉下来:-)
我遵循创建函数popen2的@slacy的想法。
但是在孩子过程死亡时发现了问题 outfp
不从功能返回。
可以通过在父进程上添加关闭未使用管道来解决。
close(p_stdin[READ]);
close(p_stdout[WRITE]);
我们可以通过使用bash作为外壳来获得正确的新过程的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);
}
显而易见的方法是系统(“ pkill process_name”);
显然,如果您的流程运行多个实例,这是有问题的。
我在Python做了类似的事情,您可以在那里杀死一个子过程和为此分配的任何子过程。实际上,这类似于Slacy的解决方案。http://www.pixelbeat.org/libs/subprocess.py
我只是将(Bash)脚本放入第一行中:
echo PID $$
然后我阅读了PID,然后使用它来做:杀死(PID,9)