代码之家  ›  专栏  ›  技术社区  ›  Ton van den Heuvel

如何避免read()在以下情况下挂起?

  •  2
  • Ton van den Heuvel  · 技术社区  · 6 年前

    char* args[] = {"/path/to/3rd/party/binary", "with", "args", NULL};
    
    int fds[2];
    pipe2(fds, O_CLOEXEC);
    
    pid_t pid = fork();
    if (pid == 0)
    {
        dup2(fds[1], STDOUT_FILENO);
        execvp(args[0], args);
        _exit(1);
    }
    else
    {
        close(fds[1]);
    
        char buf[1024];
        int bytes_read;
        while ((bytes_read = read(fds[0], buf, sizeof buf - 1)) > 0)
        {
            buf[bytes_read] = '\0';
            printf("%s", buf);
        }
    
        close(fds[0]);
        waitpid(pid, NULL, 0);
    }
    

    我没有第三方应用程序的代码,它是一个专有的二进制文件。当在终端中使用与上述代码中使用的参数相同的参数运行第三方应用程序时,它最终会完成。但是,当使用上面的代码分叉第三方二进制文件时,它不会完成,而是变成一个僵尸进程,上面的代码挂起在 read() 呼叫

    分叉的第三方二进制文件本身分叉两个守护进程(同样,我不控制专有二进制文件),我认为这是造成问题的原因。分叉的守护进程将具有重复文件描述符的副本,从而防止 从结束到结束。事实上,如果 dup2() 呼叫被替换为:

    dup3(fds[1], STDOUT_FILENO, O_CLOEXEC);
    

    有没有可能以某种方式防止这种挂在墙上的情况 在这种情况下调用,还是需要求助于某种形式的非阻塞I/O?

    更新;使用简单的 popen() 他也有同样的问题。

    (后续行动来自: read() hangs on zombie process )

    1 回复  |  直到 6 年前
        1
  •  2
  •   David Schwartz    6 年前

    你需要特别忽略SIGCHLD。收割僵尸是你的责任,但当你被封锁时,你不能这样做 read . 如果你打电话 阅读 之后 SIGCHLD 阅读 永远。