Closing Nonduplex Unnamed Pipes in C - c

I have 8 children, and am trying to use 8 pairs of nonduplex unnamed pipes to communicate with them. Thus, I have 2 pipes for each child and 16 pipes in total (one for childRead_ParentWrite and the other for parentRead_ChildWrite).
Anyway, my main question is when to close the pipes. I was taught to initially close the sides that are not being used by the process, and then when the process is finished with its side of the pipe, to close it off. However, I am brand new to the subject and am having some trouble. Here is my code:
// The 16 pipes
int fd_childReads_ParentWrites[8][2]; // Parent closes 0, Child closes 1
int fd_parentReads_ChildWrites[8][2]; // Child closes 0, Parent closes 1
// The 16 buffers
char buf_ChildReads_ParentWrites[8][80];
char buf_ParentReads_ChildWrites[8][80];
// CREATE THE PIPES
// FORK THE CHILDREN
for(playerNumber = 0; playerNumber < NUM_PLAYERS; playerNumber++)
{
pid = fork();
if (pid < 0) // Error occurred
{
printf("Fork Failed\n");
exit(1);
}
else if (pid == 0) // Child
{
break;
}
}
// MANAGE PROCESSES
if (pid == 0) // CHILD
{
printf("I am the child: %d\n", getpid());
// Close the appropriate pipe ends
close(fd_childReads_ParentWrites[playerNumber][1]);
close(fd_parentReads_ChildWrites[playerNumber][0]);
// CHILD DOES STUFF WITH PIPES
// When finished, close the working child pipe ends
close(fd_childReads_ParentWrites[playerNumber][0]);
close(fd_parentReads_ChildWrites[playerNumber][1]);
}
else // PARENT
{
printf("I am the parent: %d\n", getpid()); // NOT BEING PRINTED
// Close the appropriate pipe ends
for (i = 0; i < NUM_PLAYERS; i++)
{
close(fd_childReads_ParentWrites[i][0]);
close(fd_parentReads_ChildWrites[i][1]);
}
// PARENT DOES STUFF WITH PIPES
// Finally, close the working parent pipe ends
for (i = 0; NUM_PLAYERS < 8; i++)
{
close(fd_childReads_ParentWrites[i][1]);
close(fd_parentReads_ChildWrites[i][0]);
}
// Wait for the children
for (playerNumber = 0; playerNumber < NUM_PLAYERS; playerNumber++)
{
wait(NULL);
}
}
I must be doing something wrong. The program prints out the correct number of children, but the parent's printf() line is never printed. When I take out all of the close() functions it prints, but even taking out solely the children's close()'s doesn't print he parent line.
If someone could explain to me the correct way to close nonduplex unnamed pipes in a situation like this, that would be awesome.

Related

Creating n childs process with fork() and treat them after

I want to create n child processes by fork () inside a for loop, and treat the child processes later once they have all been created.The child processes must be treated once the
execution of the parent process has been carried out.
int main(int argc, char *argv[])
{
char cadena[STRLONG];
pid_t pid;
for(int i =0; i<5; i++){
pid = fork();
if(pid == -1){
perror("Error\n");
exit(-1);
}
else if(pid == 0){
break;
}
}
if (pid > 0){
printf("I'm the parent, --> %d\n", getpid());
}
else if(pid == 0){
printf("I'm the child --> %d \n", getpid());
exit(0);
}
for(int i = 0; i<5; i++){
wait(NULL);
}
}
This is what I have done, but the child processes are executed before they are all created and I don't know how to solve it ...
When you fork(), the parent and child process will run in parallel immediately from the place where you fork().
time parent child
| |
| |
| fork()--------+
| | |
V | | ​
There is no way of telling which one of them that does something before the other - unless you synchronize their actions in some way.
To do proper synchronization between processes you can use semaphores or some other interprocess communication technique. For this simple case, you could use the old self-pipe trick.
Create a pipe
When a child is created, close the writing end of the pipe in the child - and try reading a byte from the pipe. This will hang until there is a byte or the pipe is closed.
When all children have been created, close the reading end in the parent.
The state at this point should be:
The parent only has the write end of the pipe open.
All the children only have the read end of the pipe open, eagerly waiting for something to happen in the pipe.
When the parent want all the children to start working, close the write end of the pipe in the parent. This will cause the read operation in all the children to unblock.
There's no error checking in this below, but it'll show the idea:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
enum { P_RD, P_WR }; // pipe indices, 0 and 1
int main() {
pid_t pid;
int pip[2];
pipe(pip); // create a pipe from pip[P_WR] to pip[P_RD]
for(int i = 0; i < 5; i++) {
pid = fork();
if(pid == -1) {
perror("Error\n");
exit(1);
} else if(pid == 0) {
close(pip[P_WR]); // close write end of pipe
char ch; // dummy buffer
read(pip[P_RD], &ch, 1); // hang here until closed
close(pip[P_RD]); // close read end of pipe
printf("I'm the child --> %d \n", getpid());
exit(0);
}
}
close(pip[P_RD]); // close read end of pipe
// The state at this point:
// * The parent only has the write end of the pipe open.
// * All the children only have the read end of the pipe open.
printf("I'm the parent --> %d\n", getpid());
close(pip[P_WR]); // close write end of pipe to start children
int wstatus;
while((pid = wait(&wstatus)) != -1) {
printf("%d died\n", pid);
}
}

Creation of multiple named pipes

I am trying to make a program that makes a number of children defined by the user. The parent must use named pipes (it is a requirement) to send information back and forth with his children. So, I need to create a number of named pipes equal to the amount of children I am forking. How can I do this efficiently and have every child know what his pipe is named?
pid_t childpid;
for(i = 0; i < numWorker; i++){
// char *pipeName = "somename";
// change the pipeName to reflect the child by adding a suffix
// mkfifo(pipeName, 0666);
childpid = fork();
if(childpid < 0){
perror("fork\n");
}
else if(childpid == 0){
signal(SIGCONT, handleSignalChild);
// how can I open the fifo here and then carry on reading and writing
//inside the while() below?
break; // child exits the creation loop.
}
}
// Main program execution begins here
while(1){
if(childpid == 0){
// read and write to the already opened pipes.
//code to handle child execution.
}
else{
// open all fifo pipes and get ready to read and write stuff.
//code to handle parent execution.
}
}
EDIT: Reworded the question to make more sense.

Parent process not terminating

I have a parent and child process both counting upto 50 and then terminate. The parent process waits till the child process has counted upto 50 and then exits. I have written the code but it is going in infinite loop :
int main()
{
long int T_Child = 0, T_parent = 0;
pid_t procid = fork();
int T = 0;
if(procid < 0)
{
printf("\nFailed");
exit(0);
}
else if(procid == 0)
{//child
while(T_Child < 50)
{
printf("\nCHILD : %ld",T_Child);
delay(2);
T_Child++;
}
exit(1);
}
else if(procid > 0)
{//parent
while(T_parent < 50)
{
printf("\nPARENT : %ld",T_parent);
delay(2);
T_parent++;
}
while(T_Child < 50)
{//to ensure parent exits after child
delay(1);
}
exit(1);
}
return 0;
}
I'm a novice in this field. Please help!
Forking is not the same as threading. A fork creates a copy of the process. The
values of the variables in the child process would have the same as the
variables of the parent process at the time of the fork(). That means that
the child variables inherit the values from the parent, but changes of the
child variables are not visible by the parent.
If the parent needs to wait for the child to exit, it must call
wait or waitpid. Also if the parent needs to get a value from the child, the parent and the child
should comunicate with each other, for example using a pipe.
The following code shows how parant and child communicate with each other and
how the parent should wait for a child to exit:
#include <unistd.h>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(void)
{
int comm[2];
// create pipe
if(pipe(comm) < 0)
{
perror("Could not create pipe");
return 1;
}
pid_t pid = fork();
if(pid < 0)
{
perror("Could not fork");
close(comm[0]);
close(comm[1]);
return 1;
}
if(pid == 0)
{
// CHILD
// closing reading end of the pipe
close(comm[0]);
do_some_work();
int result = 50;
// write to the parant through the pipe
write(comm[1], &result, sizeof result);
// closing writing end
close(comm[1]);
exit(0);
}
// PARENT
// close writing end of pipe
close(comm[1]);
puts("Now waiting for the child to exit...");
// parent waits for child to exit
int child_status;
if(waitpid(pid, &child_status, 0) < 0)
{
perror("Could not wait");
close(comm[0]);
return 1;
}
// if child exited without any error
if(WIFEXITED(child_status) && WEXITSTATUS(child_status) == 0)
{
// read answer from the child
int answer;
read(comm[0], &answer, sizeof answer);
printf("Child answered with %d\n", answered);
}
// closing reading end of pipe
close(comm[0]);
return 0;
}
The child process and the parent process run in separate memory spaces. At the time of fork() both memory spaces have the same content.
There is concept called Copy on Write (CoW); it's good to have knowledge about it-
Copy on Write is an optimization where the page tables are set up so that the parent and child process start off sharing all of the same memory, and only the pages that are written to by either process are copied when needed.
[Above is copied from my own answer to an old thread]
In your program you are doing:
while(T_Child < 50)
{//to ensure parent exits after child
delay(1);
}
The T_Child is initialized with 0 before fork. Because the address spaces are separate, when the child process modifies the value of T_Child, CoW creates a copy of its page — but the parent copy of T_Child still has the initial value 0. The parent process is not making any change in the value in T_Child. So, the while loop condition T_Child < 50 will always true and the loop will execute infinitely.
Instead, you should wait for child process to exit using waitpid system call. In place of while(T_Child < 50){.. loop, you should do:
waitpid(procid,&status,0);
This will make parent process wait till child process exits.

Reading and writing about PIPE in linux

A simple multi-process program in linux.
Input some numbers like ./findPrime 10 20 30.
The program will create 3 child processes to find out all primes between 2-10, 10-20, 20-30.
Once a child process find a prime, it will write "2 is prime" through a pipe and send to the parent. Parent will print it on the screen.
THE PROBLEM here is that, I use a while loop to write message into the pipe and use another while loop on the parent side to receive the message, but with the code below, it only display the first message, so I am wondering what`s going on, how can i keep reading from that pipe? Did I miss someting? Thanks very much!
char readBuffer[100];
char outBuffer[15];
int pids[argc];
int fd[2];
pipe(fd);
for(i = 0; i < argc; i++)
{
if( i == 0)
bottom = 2;
else
bottom = args[i - 1];
top = args[i];
pids[i] = fork();
if(pids[i] == 0)
{
printf("Child %d: bottom=%d, top=%d\n", getpid(), bottom, top);
close(fd[0]);
j = bottom;
while(j <= top)
{
int res = findPrime(j);
if(res == 1)
{
sprintf(outBuffer, "%d is prime", j);
write(fd[1], outBuffer, (strlen(outBuffer)+1));
}
j++;
}
exit(0x47);
}
else if(pids[i] < 0)
{
fprintf(stderr, "fork failed! errno = %i\n", errno);
break;
}
else
{
close(fd[1]);
while((nbytes = read(fd[0], readBuffer, sizeof(readBuffer))) > 0 )
printf("%s\n", readBuffer);
int status = 0;
pid = waitpid(pids[i], &status, 0);
if(pid >= 0)
printf("Child %d exited cleanly\n", pid);
}
}
And these child process should run in the order that they were created, like when Process 1 is done, then Process 2 will run, and process 3 will after 2.
I also want the parent process display the message immediately when it receives one.
Parent/children share their file descriptors (as they presently are) at the time of the fork. Your immediate problem is that you close fd[1] in the parent. When the first child ends the fact that the process ends means that fd[1] will be automatically closed in the child. As the OS no longer has any valid references to the file descriptor it becomes invalid. So your pipe writes fail in all subsequent children.
So just don't close fd[1] in the parent.
But then you have other problems too. One that jumps out is that if one of your child processes doesn't find a prime it will never write to the pipe. The parent, however, will block forever waiting for something to read that is never going to arrive. By not closing fd[1] in the parent you won't see EOF - i.e. read() == 0 in the parent. So one solution is to pass a "done" message back via the pipe and have the parent parse that stuff out.
A better solution yet is to consider a redesign. Count the number of processes you are going to need by parsing the command line arguments right at the beginning of the program. Then dynamically allocate the space for the number of pipe descriptors you are going to need and give each process its own pair. That could avoid everything altogether and is a more standard way of doing things.

How does one use the wait() function when forking multiple processes?

Learning to use the fork() command and how to pipe data between a parent and it's children. I am currently trying to write a simple program to test how the fork and pipe functions work. My problem seems to be the correct use/placement of the wait function. I want the parent to wait for both of its children to finish processing. Here is the code I have so far:
int main(void)
{
int n, fd1[2], fd2[2];
pid_t pid;
char line[100];
if (pipe(fd1) < 0 || pipe(fd2) < 0)
{
printf("Pipe error\n");
return 1;
}
// create the first child
pid = fork();
if (pid < 0)
printf("Fork Error\n");
else if (pid == 0) // child segment
{
close(fd1[1]); // close write end
read(fd1[0], line, 17); // read from pipe
printf("Child reads the message: %s", line);
return 0;
}
else // parent segment
{
close(fd1[0]); // close read end
write(fd1[1], "\nHello 1st World\n", 17); // write to pipe
// fork a second child
pid = fork();
if (pid < 0 )
printf("Fork Error\n");
else if (pid == 0) // child gets return value 0 and executes this block
// this code is processed by the child process only
{
close(fd2[1]); // close write end
read(fd2[0], line, 17); // read from pipe
printf("\nChild reads the message: %s", line);
}
else
{
close(fd2[0]); // close read end
write(fd2[1], "\nHello 2nd World\n", 17); // write to pipe
if (wait(0) != pid)
printf("Wait error\n");
}
if (wait(0) != pid)
printf("Wait error\n");
}
// code executed by both parent and child
return 0;
} // end main
Currently my output looks something along the lines of:
./fork2
Child reads the message: Hello 1st World
Wait error
Child reads the message: Hello 2nd World
Wait error
Where is the appropriate place to make the parent wait?
Thanks,
Tomek
That seems mostly ok (I didn't run it, mind you). Your logic error is in assuming that the children will end in some particular order; don't check the results of wait(0) against a particular pid unless you're sure you know which one you're going to get back!
Edit:
I ran your program; you do have at least one bug, your second child process calls wait(), which you probably didn't want to do. I recommend breaking some of your code out into functions, so you can more clearly see the order of operations you're performing without all the clutter.
i think its better to use something like this, in order to wait for all the childrens.
int stat;
while (wait(&stat) > 0)
{}

Resources