我正在使用函数popen2(已在stackoverflow上的其他地方推荐)以编程方式创建一个必须在一段时间后再次被杀死的进程。 popen2返回一个PID,我认为这个PID可以用来杀死进程。但是,它不会以这种方式工作。为了杀死它,我必须递增返回的PID,我不明白(见下面的代码)
当各种线程并行执行此操作时,可能会出现另一个问题。在这种情况下,我认为由于竞争条件,PID可能会有不同的差异。
所以我的问题是:如何在多线程场景中可靠地识别popen2创建的进程的PID?
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#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;
}
main() {
pid_t pid;
// Create process
pid = popen2("crafty", &in, &out);
sleep(5);
// Why doesn't kill(pid, SIGKILL) work?
kill(pid+1, SIGKILL);
while (1);
}
答案 0 :(得分:6)
我想我明白了。
execl("/bin/sh", "sh", "-c", command, NULL);
运行sh
,popen2
返回它的pid。当您致电kill
时,它会杀死sh
,但不会触及其子进程command
。它实际上是一个侥幸,杀死下一个pid杀死command
。这并不总是有效,只是符合竞争条件。
如果您希望能够杀死目标进程,则必须直接启动它。
警告(未经测试的代码):
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};
在您的特定示例中:
char *command[] = {"crafty", NULL};
答案 1 :(得分:1)
您可以使用shell的'exec'命令来避免挂起进程。另外:popen2应关闭未使用管道的写入端,否则管道保持打开状态。如果其中一个指针(infp,outpf)为NULL,则创建并立即关闭管道是没用的。这是我在项目中使用的popen2的版本:
pid_t popen2(char *command, int *in_fd, int *out_fd) {
int pin[2], pout[2];
pid_t pid;
char cmd[strlen(command)+10];
if (out_fd != NULL) {
if (pipe(pin) != 0) return(-1);
}
if (in_fd != NULL) {
if (pipe(pout) != 0) {
if (out_fd != NULL) {
close(pin[0]);
close(pin[1]);
}
return(-1);
}
}
pid = fork();
if (pid < 0) {
if (out_fd != NULL) {
close(pin[0]);
close(pin[1]);
}
if (in_fd != NULL) {
close(pout[0]);
close(pout[1]);
}
return pid;
}
if (pid==0) {
if (out_fd != NULL) {
close(pin[1]);
dup2(pin[0], 0);
}
if (in_fd != NULL) {
close(pout[0]);
dup2(pout[1], 1);
}
// Exec makes possible to kill this process
sprintf(cmd, "exec %s", command);
execlp("sh", "sh", "-c", cmd, NULL);
fprintf(stderr, "%s:%d: Exec failed in popen2. ", __FILE__, __LINE__);
perror("Error:");
exit(1);
}
if (in_fd != NULL) {
close(pout[1]);
*in_fd = pout[0];
}
if (out_fd != NULL) {
close(pin[0]);
*out_fd = pin[1];
}
return pid;
}