In a problem given by university we have to pipe
from a parent process(P1) to its child P2, and afterwards P2 must pipe to another child of P1, the other child is P3. Both P2 and P3 are to be written in c and made into executable files. They will then by exec
ed by child processes in P1.
P1 writes the numbers 1 to 10000 to stdout
, P2 reads them through its stdin
, removes the numbers divisible by 2, and writes the result to its stdout
. P3 reads those numbers through its stdin
, filters out the results that are divisible by 3, and writes everything to a file.
I have managed to implement absolutely everything, but my child processes do not end. The reason for this, I believe, is that I have used the following method to read the input in each child:
while(n=read(0, &i, sizeof(i))>0)
The problem here, as I understand it, is that read
blocks when it doesn't get any bytes. As P1 writes the 10000 numbers using:
for(i=1; i<=10000; i++){
write(1, &i, sizeof(i));
}
Neither child process ever has any reason to believe that no more data is coming its way. Therefore, each read
simply blocks waiting for a byte that will never come.
Can anyone suggest a way to overcome this roadblock?
The code of each process is as follows:
Parent:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<string.h>
#include<sys/wait.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
// pipe to send input string from parent
// Child prints to file
int fd1[2]; // Used to store two ends of first pipe
int fd2[2]; // Used to store two ends of second pipe
//variables
int n, i, status1, status2;
char *args1[]={"./Div2",NULL};
char *args2[]={"./Div3",NULL};
//child process ids
pid_t pid1, pid2;
//open pipe 1
if (pipe(fd1)==-1)
{
fprintf(stderr, "Pipe 1 Failed" );
return 1;
}
//open pipe 2
if (pipe(fd2)==-1)
{
fprintf(stderr, "Pipe 2 Failed" );
return 1;
}
//create child 1
pid1 = fork();
if(pid1<0){
printf("Error creating child1\n");
return(1);
}
if(pid1==0){ //child1
if(close(fd1[1])<0){ //child does not write to pipe 1
error();
}
if(close(fd2[0])<0){ //child does not read from pipe 2
error();
}
dup2(fd1[0], 0); //redirect stdin
dup2(fd2[1], 1); //redirect stdout
execvp(args1[0],args1);
if(close(fd1[0])<0){ //close used pipe
error();
}
if(close(fd2[0])<0){ //close used pipe
error();
}
exit(0);
}
pid2=fork();
if(pid2<0){
printf("Error creating child2\n");
return(1);
}
if(pid2==0){ //child2
if(close(fd1[0])<0){ //child does not use pipe 1
error();
}
if(close(fd1[1])<0){
error();
}
if(close(fd2[1])<0){ //child does not write to pipe 2
error();
}
dup2(fd2[0], 0); //redirect stdin
execvp(args2[0], args2);
if(close(fd2[0])<0){ //close pipe after use
error();
}
exit(0);
}
//parent
//parent doesn't read from the pipe
if(close(fd1[0])<0){
error();
}
if(close(fd2[0])<0){
error();
}
if(close(fd2[1])<0){
error();
}
dup2(fd1[1], 1); //redirect stdout
for(i=1; i<=10000; i++){
write(1, &i, sizeof(i));
}
if(close(fd1[1])<0){
error();
}
int returnedPID1=waitpid(pid1, &status1, 0);
if(returnedPID1==pid1){
printf("Parent waited for child as predicted\n");
}
int returnedPID2=waitpid(pid2, &status2, 0);
if(returnedPID2==pid2){
printf("Parent waited for child as predicted\n");
}
_exit(0);
}
P2 (includes excluded)
int main()
{
int n;
int i;
while((n=read(0, &i, 4))>0){
if((i%2)!=0){
write(1, &i, sizeof(i));
}
}
return;
}
P3
int main()
{
int n;
int i;
char tmp[12] = {0x0};
char *arg[]= {"/home/eric/Documents/pr3/test.txt"};
int fp = open(arg[0], O_WRONLY|O_CREAT|O_TRUNC, 0666);
if(fp<0){
printf("Error opening file\n");
_exit(1);
}
while((n=read(0, &i, 4))>0){
if((i%3)!=0){
sprintf(tmp,"%11d", i);
write(fp, tmp, strlen(tmp));
}
}
return;
}
Thanks guys.
Except in case of error, exec never returns. So when you write:
execvp(args1[0],args1);
if(close(fd1[0])<0){ //close used pipe
error();
}
you are wrong to expect the file descriptor to be closed. Close them before you exec. They are getting left open. Although in your particular case the problem is that the parent never closes fd 1. The parent has two file descriptors that are writing into the pipe ( fd[1]
and 1
), and you need to close them both before the child reading the pipe will finish.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.