2016-09-26 115 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. 即使管道寫端沒有關閉,爲什麼從讀端讀取產生父進程中的線程輸出,而不是阻塞,或返回一些錯誤?

如果有人能說明這一點,將不勝感激。

相關問題