2016-01-15 26 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在执行似乎完成后有输出,使其看起来像悬挂当它不是。

的解决方案是用少量重组创建从父进程两个管道和叉子。

特别感谢罗素里德谁帮我出。