子进程输出的重定向

时间:2016-09-26 16:41:26

标签: c++ redirect child-process

我正在重定向子进程的输出:

int pipefd[2];
pipe(pipefd);
pid_t pid = fork(); /* Create a child process */

switch (pid) {
case -1: /* Error */
    cout << "Uh-Oh! fork() failed.\n";
    exit(1);
case 0: /* Child process */
    close(pipefd[0]);
    dup2(pipefd[1], 1);
    dup2(pipefd[1], 2);
    close(pipefd[1]);
    execv(args[0], (char * const *)args);
    cout << "execv() error" << endl;
    exit(1);
default: /* Parent process */
    close(pipefd[1]);
    char buffer[1024];
    size_t bytes_read = 0;
    bytes_read = read(pipefd[0], buffer, sizeof(buffer));
    if(bytes_read == -1) {
        cout << "read() error" << endl;
        exit(1);
    }

    close(pipefd[0]);

    if(bytes_read > 0) {
        buffer[bytes_read-1] = '\0'; // Overwrite the newline
    }

    int status, exit_pid;
    while(true) {
        exit_pid = waitpid(pid, &status, 0);
        if(exit_pid == -1) {
            cout << "waitpid() error: " << strerror(errno) << endl;
            exit(1);
        }
        else {
            return WEXITSTATUS(status);
        }
    }
}

当我将它作为一段孤立的代码运行时,这很好用。但是当我将它集成到我的多线程环境中时,会发生一件可怕的事情:read()调用以某种方式读取父进程的其他线程的输出,就好像它是子进程管道的输出一样。 有没有遇到过这样的事情? 我是OS X.

1 个答案:

答案 0 :(得分:0)

好吧,我有一个解决方案,即使我不完全理解为什么会这样。

但首先,应该清楚这种行为既不正常也不可预期。使用fork()创建的子进程不会从其父级继承任何正在运行的线程(因此意外输出必须来自父线程)。它有自己的描述符表。因此,当子进程调用dup2()来改变其输出描述符时,这不应该对父进程中的线程产生任何影响。

仅在execv()调用失败的情况下才会出现此问题。在这些情况下,我期望终止子进程以关闭其所有文件描述符。但这没有发生,或者至少它与明确调用close()没有相同的效果。因此,在execv()之后添加显式的close()调用可以解决问题:

execv(args[0], (char * const *)args);
close(1);
close(2);
exit(1);

管道的写端描述符的关闭将导致读端上的读操作接收0,因此知道不再读取。 但是,我仍然不知道以下内容:

  1. 为什么子进程中对exit()的调用等同于显式调用close()?
  2. 即使管道写入端没有关闭,为什么从读取端读取会产生父进程中的线程输出,而不是阻塞或返回一些错误?
  3. 如果有人能够阐明这一点,我们将不胜感激。