2016-11-14 83 views
0

我試圖編寫一個程序C創建2個子進程,其中每個進程執行execvp管道問題:第一個孩子寫入太多

我的問題是,第一個孩子寫太多的輸入到另一個孩子讀的管道。

int main(int argc, char* argv[]){ 

//unnamed pipe 
int pipeFd[2], statusFirst,statusSecond; 
pid_t childPidOne,childPidTwo; 

if(pipe(pipeFd) < 0){ 
    perror("Pipe error:\n"); 
    exit(EXIT_FAILURE); 
} 

switch(childPidOne = fork()){ 
    case -1: 
     perror("First Fork error:\n"); 
     exit(EXIT_FAILURE); 
    case 0: 
     printf("First child\n"); 
     close(pipeFd[1]); 
     if((execvp(argv[1], &argv[1])) < 0){ 
      perror("First execvp error:\n"); 
     } 
     printf("End First cild\n"); 
     exit(0); 
    default: 
     //Do nothing 
     break; 
} 

switch(childPidTwo = fork()){ 
    case -1: 
     perror("Second Fork error:\n"); 
     exit(EXIT_FAILURE); 
    case 0: 
     printf("Second cild\n"); 
     close(pipeFd[0]); 
     if((execvp(argv[3], &argv[3])) < 0){ 
      perror("Second execvp error:\n"); 
     } 
     printf("End Second cild\n"); 
     exit(0); 
    default: 
     //Do nothing 
     break; 
} 


close(pipeFd[0]); 
close(pipeFd[1]); 


if((waitpid(childPidOne,&statusFirst,WUNTRACED | WCONTINUED)) < 0){ 
    perror("First waitpid error:\n"); 
}else{ 
    if (WIFEXITED(statusFirst)) { 
     printf("First exited, status=%d\n", WEXITSTATUS(statusFirst)); 
    } else if (WIFSIGNALED(statusFirst)) { 
     printf("First killed by signal %d\n", WTERMSIG(statusFirst)); 
    } else if (WIFSTOPPED(statusFirst)) { 
     printf("First stopped by signal %d\n", WSTOPSIG(statusFirst)); 
    } else if (WIFCONTINUED(statusFirst)) { 
     printf("First continued\n"); 
    } 
} 


if((waitpid(childPidTwo,&statusSecond,WUNTRACED | WCONTINUED)) < 0){ 
    perror("Second waitpid error:\n"); 
} 
if (WIFEXITED(statusSecond)) { 
    printf("Second exited, status=%d\n", WEXITSTATUS(statusSecond)); 
    } else if (WIFSIGNALED(statusSecond)) { 
    printf("Second killed by signal %d\n", WTERMSIG(statusSecond)); 
    } else if (WIFSTOPPED(statusSecond)) { 
    printf("Second stopped by signal %d\n", WSTOPSIG(statusSecond)); 
    } else if (WIFCONTINUED(statusSecond)) { 
     printf("Second continued\n"); 
     } 

    exit(0); 
return 0; 
    } 

也許我有管+叉+ execvp是如何工作的,所以讓我告訴你,我在我的代碼正在做一個錯誤的認識:

  1. 我創建一個未命名的管道 - 無論是孩子的使用相同的管道
  2. 我會通過派生他們
  3. 創建兩個孩子的因爲我執行我的計劃是這樣的:./pipeline [FIRST SYSTEM CALL] | [SECOND SYSTEM CALL]或只給你一個例子:./pipeline echo Hello | wc -m我關閉了管道的閱讀網站
  4. 然後調用execvp(argv[1], &argv[1])

而這正是錯誤發生(我猜): 我從來沒有關閉寫入一側,直到第二個孩子呢,因爲如果成功execvp將一去不復返。

而且我知道execvp不會關閉打開的文件描述符(它可以通過使用fcntl中的標誌來關閉,如What does the FD_CLOEXEC flag do?中所述)。

示例

讓我舉一個例子。

echo Hello | wc -m 

輸出該結果

由於系統調用wc(字數)計數在給定的String

這是正確的字符(-m),因爲你好= 5 + 1(這是\n\0我猜)這使得6。現在

,運行我的程序給出結果

或瞭解更多信息

echo hello | wc 

輸出

1(行)1(字)6(字符)

而且./pipeline echo hello | wc

輸出

3(行)9(字)56(字符)

我搜索了好幾天,但我想不出它出。

任何想法?

非常感謝!

+1

如果您使用'./pipeline echo hello | wc'來運行你的程序,那麼它不會做你認爲的那樣。你的程序看到'argv [1] == echo','[2] == hello'和_nothing else_。然後將程序的(組合)輸出傳送到'wc'中。爲了(完全)實現我認爲你想要做的事情,你需要轉義管道字符並在你的代碼中檢測它(所以你知道命令行的哪些部分要傳遞給每個子進程)。 – TripeHound

+0

@TripeHound,我通過輸入./pipeline echo hello \ |手動逃過角色。 wc和它適用於我,除了第二個孩子在交互模式下啓動wc(等待輸入並按ctrl + d標記輸入結束)。這給了我1 1 6的正確結果。這意味着第一個孩子的輸入被忽略。有任何想法嗎 ? –

回答

0

自己解決了。

忘記使用dup2

只需在close命令後鍵入dup2命令,你就會沒事的。