Reputation: 797
Can anyone give my any idea why my following codes trying to implement multiple pipes are incorrect? I am implementing a parent-child relationship, so no parent-grandchildren relationships are allowed, i.e, all the children should run in parallel. When i input the command ls | cat | cat, the contents of ls are output, but the prompt still prompt me for input and it won't stop even if I input another character. Am I doing this in a wrong way?
int i;
int pipefd[num_of_pipe][2];
pid_t child_pid[num_of_child];
for (i = 0; i < num_of_child; i++) {
pipe(pipefd[i]);
if ((child_pid[i] = fork()) == 0) {
if (i == 0) {
close(pipefd[i][0]);
dup2(pipefd[i][1], STDOUT_FILENO);
close(pipefd[i][1]);
/* execvp something; */
} else if (i == num_of_child - 1) {
close(pipefd[i - 1][1]);
dup2(pipefd[i - 1][0], STDIN_FILENO);
close(pipefd[i - 1][0]);
/* execvp something */
} else {
close(pipefd[i - 1][1]);
dup2(pipefd[i - 1][0],0);
close(pipefd[i - 1][0]);
close(pipefd[i][0]);
dup2(pipefd[i][1],1);
close(pipefd[i][1]);
/* execvp something */
}
}
}
int k;
for (k = 0; k < num_of_child; k++) {
waitpid(child_pid[k], NULL, WUNTRACED);
printf("the %dth child returns\n", k + 1);
}
int j;
for (j = 0; j < num_of_pipe; j++) {
close(pipefd[j][0]);
close(pipefd[j][1]);
}
}
Upvotes: 0
Views: 3019
Reputation: 181724
The problem is that your two cat
processes are each waiting for more data on their standard inputs, because not all copies of the file descriptors for the write ends of the pipes to them get closed. This arises because the parent process builds and keeps an array of all the pipe file descriptors, and closes them only after forking all the children. Every child therefore inherits every open file descriptor the parent has so far created, not only the ones intended for its own use. Until all FD's for the write end of a pipe are closed, EOF will not be detected at the read end.
Thus, in particular, the third child process has an open file descriptor for the write end of the pipe being read by the second child process. It would close that upon exit, but it does not exit because the second process holds open the write end of the pipe feeding the third. The problem would be worse if the pipeline were longer.
You should handle the problem by having the master process close file descriptors as soon as they are no longer needed, so that they will not be inherited. With your current code structure you could do that at the bottom of your fork loop.
As a secondary matter, you should always check the return values of your function calls for error indicators if you in fact depend on them not to have failed.
Upvotes: 1