2016-09-26 84 views
-1

我从一个子进程重定向输出:重定向子进程输出

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.

+0

其他线程使用stdout和stderr来写输出吗?那么这种行为绝对是正常的和可以预料的。 –

+0

是的,但我不明白为什么这会导致这种行为。 pipe()调用分配新的文件描述符,并且子节点中的dup2()不影响父节点描述符表。 – Yuval

+0

你知道什么['dup2(pipefd [1],1);'](http://man7.org/linux/man-pages/man2/dup.2.html),你知道吗? –

回答

0

嗯,我有一个解决方案,即使我不完全明白为什么发生这种情况。

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

该问题仅在execv()调用失败的情况下发生。在这些情况下,我期望终止子进程关闭其所有文件描述符。但是这并没有发生,或者至少它没有与明确调用close()相同的效果。所以加入明确的关闭()execv后调用()解决了这个问题:

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

管道的写入终止描述符的接近是什么将导致在读端的读取操作接收0,从而知道不再读。 不过,我还是不知道以下内容:

  1. 为什么不调用exit()的子进程等同于显式调用close()方法?
  2. 即使管道写端没有关闭,为什么从读端读取产生父进程中的线程输出,而不是阻塞,或返回一些错误?

如果有人能说明这一点,将不胜感激。

相关问题