I want to have one parent with 2 children.
The parent reads from file "a.txt" and sends trough pipe to first child; the first child reads the chars and sends to the second child the lower letter chars.
The second child prints in "b.txt" each distinct char and number of appearances(per line) and then sends trough a pipe to the parent the number of distinct chars. The parent prints the result from the second child.
I've done the pipe from parent to 1 child and to test I've put a pipe back to the parent.
What I can't figure it out is how to make the pipe go to the second child. I've been searching for information on dup2 but I don't get on how to make it work.
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <ctype.h>
#include <fcntl.h>
void main()
{
int pfd1[2], pfd2[2], pid1, pid2, pfin, status, fd;
char *c = (char *)malloc(sizeof(char));
if (pipe(pfd1) < 0) {
printf("Eroare la crearea pipe-ului\n");
exit(1);
}
if (pipe(pfd2) < 0) {
printf("Eroare la crearea pipe-ului\n");
exit(1);
}
if ((pid1 = fork()) < 0) {
printf("Eroare la fork\n");
exit(1);
}
if (pid1 == 0) { /*child */
close(pfd1[1]);
while (read(pfd1[0], c, 1) > 0) {
//printf("%s",c);
if (islower(*c)) {
close(pfd2[0]);
//inchid capul de citire; scriu in pipe
write(pfd2[1], c, 1);
////dup??????
}
}
printf("\n");
write(pfd[1], buff, len);
close(pfd1[0]);
close(pfd2[1]);
exit(0);
}
if ((pid2 = fork()) < 0) {
printf("Eroare la fork\n");
exit(1);
}
if (pid2 == 0) {
printf("second child");
exit(0);
}
/* parent */
close(pfd1[0]);
close(pfd2[1]);
fd = open("date.txt", O_RDONLY);
while (read(fd, c, 1) > 0) {
write(pfd1[1], c, 1);
}
close(pfd1[1]); /* la sfarsit inchide si capatul utilizat */
close(pfin);
while (read(pfd2[0], c, 1) > 0)
printf("%s", c);
close(pfd2[0]);
printf("%d", wait(&status));
printf("%d", wait(&status));
}
I have a few specific comments on your code:
While there is nothing wrong with this, there is also no need for this
charto be allocated from the heap. The more idiomatic approach would usechar c;here and then pass&ctoread(2)andwrite(2)system calls. (Even more idiomatic would be to use the C Standard IO facility;freopen(3),getchar(3), andputchar(3)-- but do not make that transition until you have this code working exactly as you want it to, because it is an additional complication with the problem you're trying to solve.)By using your own error message, you are missing out on important error information. You should use
perror(3)to print an error message instead. This will give you and your users an actual cause for errors that they can search for.fork(2)can fail if your user is running into thesetrlimit(2)NPROCmaximum process limit, the system-wide process limit, out of kernel memory.You should also check the return value from
open(2)calls. (You're supposed to also check the return values fromwrite(2)andclose(2)for errors, but handling these errors is harder. Simply printing the error and quitting is a good start for most programs.)This is the wrong location for the
close(2)call -- you shouldn't be closing this filedescriptor over and over for every input character. If you were checking theclose(2)return value, you would noticeerrnois set toEBADFbecause the file descriptor is no longer valid on the second and subsequent calls.Now, onto the problem you came here for: the sequence of
fork(),pipe(), anddup2()calls that will hook up all your processes in a pipeline and send data back to the parent process. Sincepipe(2)creates uni-directionalpipe(7)s, you need to callpipe(2)four times -- for both directions between parent and children. If you store the pipe endpoints in arrays with names that mean something to you, they will be easier to keep track of. Perhaps create arrays namedto_for writing into andfrom_for reading from:Note that you don't actually need to use
dup2(2)to re-arrange the filedescriptors unless you want to execute other programs to handle the "filter" task. Justread(2)using thefrom_parent[...]orfrom_child[...]descriptors andwrite(2)to theto_child[...]andto_parent[...]descriptors.Maybe the entire thing would be easier with
socketpair(2)usingAF_UNIXto create bi-directional sockets, which can then be read from and written to in the same fashion as any other BSD-style socket. Seesocket(7)andunix(7)for an overview.