C 通过管道将子进程导入另一个子进程
我正在尝试创建两个管道,第一个管道的输入是父进程的C 通过管道将子进程导入另一个子进程,c,linux,pipe,fork,system-calls,C,Linux,Pipe,Fork,System Calls,我正在尝试创建两个管道,第一个管道的输入是父进程的argv[1]中输入文件的内容,逐行输入到一个mapper进程中,该进程执行一些工作,最后输入到一个reducer进程中,该进程将其减少 当我在“bash”中运行我的mapper和reducer时: ./mapper < input.txt | reducer 问题是,如果在dup之后有多个fd,则在发送EOF时,必须关闭原始的dup 简而言之,对于dup,将增加FD引用计数 另一个问题是,我的进程树是线性的,而不是一个进程的两个子进程,
argv[1]
中输入文件的内容,逐行输入到一个mapper
进程中,该进程执行一些工作,最后输入到一个reducer
进程中,该进程将其减少
当我在“bash”中运行我的mapper
和reducer
时:
./mapper < input.txt | reducer
问题是,如果在
dup
之后有多个fd
,则在发送EOF
时,必须关闭原始的dup
简而言之,对于dup
,将增加FD
引用计数
另一个问题是,我的进程树是线性的,而不是一个进程的两个子进程,因此主进程在输出之前退出,导致bash在执行似乎完成之后有输出,使它看起来像是挂起的,而不是挂起的
解决方案是从父进程创建管道和分支,只需稍加重组
特别感谢帮助我的Russell Reed。while(read=getline(&line,&n,in)!=-1)-->while(read=getline(&line,&n,in))!=-1)添加了括号没有改变任何东西除了terence调用的错误之外,还应该将变量“read”传递给write调用,而不是“n”n'是分配的空间量,通常大于实际读取量,导致重复写入某些相同的数据。这就是为什么你没有看到特伦斯的建议有任何变化。这两个更改为我修复了输出,但我还没有解决您的wait()问题。捕捉得好!不幸的是,它无法解决问题,在我调用exec后,孩子们似乎没有做任何事情……但是exec也不会抛出任何错误。我用/bin/cat替换了您的映射程序和减速器程序,以简化故障排除。我得到了正确的回显输入,但是第一个cat进程挂起,试图从管道读取更多数据(我运行strace查看系统调用)。
#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);
}
}