2016-01-15 73 views
1

我正在試圖創建兩個管道,第一個輸入的內容是輸入文件的父進程argv[1]中的行一行一行地輸入到mapper進程中一些工作,然後最終進入一個reducer進程,從而減少它。將子進程管道插入另一個子進程

當我跑我mapperreducer像這樣的`bash下

./mapper < input.txt | reducer 

它可以完美的,但下面的程序什麼也不輸出和掛在wait(NULL);

我的代碼

#include <unistd.h> 
#include <sys/types.h> 
#include <sys/wait.h> 
#include <stdlib.h> 
#include <stdio.h> 

void checkForkError(pid_t pid); 
void mapperSetup(int mapperPipe[]); 
void reducerSetup(int reducerPipe[]); 

int main(int argc, char* argv[]) { 
    if(argc < 2) { 
     printf("please specify an input file\n"); 
     exit(1); 
    } 
    int mapperPipe[2]; //last index write end, first index read end 

    if (pipe(mapperPipe) == -1) { 
      perror("error piping"); 
      exit(EXIT_FAILURE); 
    } 

    pid_t firstChild = fork(); 

    checkForkError(firstChild); 

    if(firstChild == 0) { //child 
     mapperSetup(mapperPipe); 
    } 
    else { 
     close(mapperPipe[0]); 
     close(STDOUT_FILENO); 
     dup(mapperPipe[1]); 
     FILE* in = fopen(argv[1], "r"); 
     if(in == NULL) { 
      perror("error opening file"); 
      exit(EXIT_FAILURE); 
     } 
     ssize_t read; 
     size_t n; 
     char* line = NULL; 
     while(read = getline(&line, &n, in) != -1) { 
      write(STDOUT_FILENO, line, n); 
     } 
     close(STDOUT_FILENO); 
     free(line); 
     wait(NULL); 
    } 
} 

void inline checkForkError(pid_t pid) { 
    if(pid < 0) { 
     perror("error forking!!!"); 
    } 
} 

void mapperSetup(int mapperPipe[]) { 
    int reducerPipe[2]; 

    if(pipe(reducerPipe) == -1) { 
     perror("error piping"); 
     exit(EXIT_FAILURE); 
    } 

    pid_t secondChild = fork(); 

    checkForkError(secondChild); 
    if(secondChild == 0) { //reducer process 
     reducerSetup(reducerPipe); 
    } 
    else { //mapper process 
     close(mapperPipe[1]); //close write end 
     close(STDIN_FILENO); //close stdin 
     dup(mapperPipe[0]); //dup pipe out to stdin 

     close(reducerPipe[0]); //close read end 
     close(STDOUT_FILENO); //close stdout 
     dup(reducerPipe[1]); //dup output to reducer pipe 

     if(execv("mapper", (char *[]){"mapper", NULL}) == -1) { 
      perror("exec error"); 
      exit(EXIT_FAILURE); 
     } 
    } 
} 

void reducerSetup(int reducerPipe[]) { 
    close(reducerPipe[1]); //close write end of second pipe 
    close(STDIN_FILENO); //close stdin 
    dup(reducerPipe[0]); //dup read end of pipe to stdin 

    if(execv("reducer", (char *[]){"reducer", NULL}) != -1) { 
     perror("exec error"); 
     exit(EXIT_FAILURE); 
    } 
} 
+0

while(read = getline(&line,&n,in)!= -1)---> while((read = getline(&line,&n,in))!= -1)添加括號 –

+0

nope沒有改變任何東西 –

+0

除了terence出來的錯誤之外,你還應該把變量'read'傳遞給你的write調用,而不是'n'。 'n'是分配的空間量,通常大於實際讀取的數量,導致一些相同的數據被重複寫入。這就是爲什麼你沒有看到特倫斯的建議有任何改變。這兩個更改已經爲我確定了輸出,但我還沒有發現你的wait()問題。 –

回答

1

的問題是,當你有多個fd's一個dup後,當你爲EOF進行發送,你必須關閉原有以及新dup

總之,FD引用計數遞增一個dup

另一個問題是,我的進程樹是線性的,而不是一個進程的兩個子進程,所以主進程在輸出之前退出,導致bash在執行似乎完成後有輸出,使其看起來像懸掛當它不是。

的解決方案是用少量重組創建從父進程兩個管道和叉子。

特別感謝羅素裏德誰幫我出。