Question

I'm trying to create a parent and a child processes that would communicate through a pipe. I've setup the child to listen to its parent through a pipe, with a read command running in a while loop.

In order to debug my program I print debug messages to the standard output (note that my read command is set to the pipe with a file descriptor different than 0 or 1). From some reason these debug messages are being received in the read command of my child process. I can't understand why this is happening. What could be causing this? What elegant solution do I have to solve it (apart from writing to the standard error instead of output)?

This code causes an endless loop because of the cout message that just triggers another read. Why? Notice that the child process exists upon receiving a CHILD_EXIT_CODE signal from parent.

int myPipe[2]
pipe(myPipe);
if(fork() == 0)
{
    int readPipe = myPipe[0];
    while(true)
    {
        size_t nBytes = read(readPipe, readBuffer, sizeof(readBuffer));
        std::cout << readBuffer << "\n";
        int newPosition = atoi(readBuffer);
        if(newPosition == CHILD_EXIT_CODE)
        {
              exit(0);
        }
    }
}

Edit: Code creating the pipe and fork

Was it helpful?

Solution

I do not know what is doing your parent process (you did not post your code), but because of your description it seems like your parent and child processes are sharing the same stdout stream (the child inherits copies of the parent's set of open file descriptors; see man fork)

I guess, what you should do is to attach stdout and stderr streams in your parent process to the write side of your pipes (you need one more pipe for the stderr stream)

This is what I would try if I were in your situation (in my opinion you are missing dup2):

pid_t pid;              /*Child or parent PID.*/
int out[2], err[2];     /*Store pipes file descriptors. Write ends attached to the stdout*/
                        /*and stderr streams.*/
// Init value as error.
out[0] = out[1] = err[0] = err[1]  = -1;

/*Creating pipes, they will be attached to the stderr and stdout streams*/  
if (pipe(out) < 0 || pipe(err) < 0) {
    /* Error: you should log it */
    exit (EXIT_FAILURE);
}

if ((pid=fork()) == -1) {
    /* Error: you should log it */
    exit (EXIT_FAILURE);
}

if (pid != 0) {
    /*Parent process*/
    /*Attach stderr and stdout streams to your pipes (their write end)*/
    if ((dup2(out[1], 1) < 0) || (dup2(err[1], 2) < 0)) {   
        /* Error: you should log it */
        /* The child is going to be an orphan process you should kill it before calling exit.*/
        exit (EXIT_FAILURE);
    }

    /*WHATEVER YOU DO WITH YOUR PARENT PROCESS*/

    /* The child is going to be an orphan process you should kill it before calling exit.*/
    exit(EXIT_SUCCESS);
}
else {
    /*Child process*/
}

You should not forget a couple of things:

  1. wait or waitpid to release associated memory to child process when it dies. wait or waitpid must be called from parent process.
  2. If you use wait or waitpid you might have to think about blocking SIGCHLD before calling fork and in that case you should unblock SIGCHLD in your child process right after fork, at the beginning of your child process code (A child created via fork(2) inherits a copy of its parent's signal mask; see sigprocmask). .
  3. Something that many times is forgotten. Be aware of EINTR error. dup2, waitpid/wait, read and many others are affected by this error.
  4. If your parent process dies before your child process you should try to kill the child process if you do not want it to become an orphan one.
  5. Take a look at _exit. Perhaps you should use it in your child process instead of exit.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top