使用popen2创建的杀戮过程

che*_*web 0 c process exec popen

我正在使用函数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); 
}
Run Code Online (Sandbox Code Playgroud)

Ser*_* L. 6

我想我明白了.

execl("/bin/sh", "sh", "-c", command, NULL);
Run Code Online (Sandbox Code Playgroud)

运行shpopen2返回它的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;
}
Run Code Online (Sandbox Code Playgroud)

并以形式传递命令

char *command[] = {"program", "arg1", "arg2", ..., NULL};
Run Code Online (Sandbox Code Playgroud)

在您的特定示例中:

char *command[] = {"crafty", NULL};
Run Code Online (Sandbox Code Playgroud)

  • 这是因为死亡过程需要由其父母收集/清理.当一个子进程死掉它变成一个僵尸,`ps`将它标记为`Z`和`<defunct>`.一个垂死的进程向它的父进程发送一个`SIGCHLD`信号,并且可以通过系统调用的`wait`系列进行收集.shell会自动执行此操作,而用户程序则不会.一个简单的解决方案就是在杀死之后调用`wait(0);`(注意:如果孩子因任何原因不死,将永远等待).有关僵尸进程的更多信息,请阅读http://en.wikipedia.org/wiki/Zombie_process. (2认同)