Reputation: 41
I have been having a hard time understanding how the command pipe() works in C. As far as I know anonymous pipes are used to send/receive information between two "related" processes.
I am finding the conditions for reading and writing into/from the corresponding file descriptor very confusing and do not understand why the read fd must be closed in order to write and viceversa, and how this, in turn can be used to block a process until another has read or written.
How can pipes be used to synchronize processes? For instance how would the following process hierarchy be implemented using pipe()?
A / B ----D\
\ C ------\
E
-A must finish before B and C are created.
-B must finish before D is created.
-C and C must finish before E is created.
-B and C may finish in any order
Many thanks for your help
Upvotes: 2
Views: 2444
Reputation: 985
I have simulated the process synchronisation that you have mentioned and also provided comments. Hope the concept will be clear now.
Note here no data is read here over the pipe, it is only used to achieve synchronisation, by using the blocking nature of the read function, when write end(s) of a pipe is still open.
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/wait.h>
#define MAXBUF 1
int main(){
int ret, i, fd[2];
char buf[MAXBUF];
//Create a Pipe
pipe(fd);
ret = fork();//Creating process A
if (0 == ret)
{
printf("Process - A created\n");
exit(0);
}
//I need to wait till Process - A completes
//Let me close my write end else I will be blocked for ever in the loop below
close(fd[1]);
//Waiting over reading the pipe -> The loop will come out when Process A exits
//Why ->since all the write ends of the pipe are closed, so read returns 0
while ((ret = read(fd[0], buf, MAXBUF)) > 0)
{
//Just Wait, the read blocks till A exits and then read returns 0
}
//Again a pipe to synchronise B and C
pipe(fd);
//Lets Create Now B and C
ret = fork();
if (0 == ret)
{
printf("Process - B created\n");
exit(0);
}
ret = fork();
if (0 == ret)
{
printf("Process - C created\n");
exit(0);
}
//Let me close my Write End of pipe
close(fd[1]);
//Here Waiting for Termination of both B and C who can terminate in any order.
while ((ret = read(fd[0], buf, MAXBUF)) > 0)
{
//This loop will turn false only if both B & C have exited.
//Since both the write ends of the pipe that
//were there in B and C will no longer be available
//after they exit and thus the read will return 0
//Just Wait ..Do nothing
}
//Now all A, B, C are finished.
//Create D and E
ret = fork();
if (0 == ret)
{
printf("Process - D created\n");
exit(0);
}
ret = fork();
if (0 == ret)
{
printf("Process - E created\n");
exit(0);
}
//Here let the main process wait for all the 5 Child to complete
//This is not needed, but I gave given so that the Shell
//Prompt is shown after the code exits..
//If this is deleted then you need to press return
//to get back the shell prompt after the code completes execution.
for (i = 0; i < 5; i++)
{
wait(NULL);
}
}
Upvotes: 2
Reputation: 409356
Pipes are not used for process synchronization, not directly anyway. Instead it's a way to communicate.
For example, a process creates a pair of pipes (one write-end and one read-end), then forks so a new child process is created. The parent can then send data to the child process through the pipe.
Upvotes: 1