Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I chain stdout in one child process to stdin in another child in C?

I've been messing around in C trying to figure out how to do this. Let's say I have my main program, the parent process. The parent creates three child processes, each of which will eventually run programs (but that's not important right now). What I'd like to do is make it so that the first child's stdout will be received by the second child's stdin. The second child's stdout will then be received by the third child's stdin. The parent process's stdin/stdout aren't messed with at all.

So far, what I've got is

pipe(procpipe);

parentPid = getpid();

for(i = 0; i < 3; i++)
{
    if(getpid() == parentPid)
    {
        child[i] = fork();
        if(child[i] == 0)
        {
            mynumber = i+1;
        }
    }
}

But from there I'm kind of stuck as to how to use dup2 to properly assign my pipes, and in which section of my code to insert it. There are lots of examples on Google and this website of how to pipe from a parent to a child, but I'm yet to see one that will tell me exactly how to connect a child's stdout to another child's stdin.

Edit: Forgot to mention: assume all my variables are properly initialised. The int 'mynumber' is so a child process knows upon creation which number it is, so I can give it instructions via

if(mynumber == whatever)
like image 328
buggritall Avatar asked Sep 02 '11 10:09

buggritall


People also ask

Does child process inherit stdout?

The stdin handle to the child process, if any, will be closed before waiting. This helps avoid deadlock: it ensures that the child does not block waiting for input from the parent, while the parent waits for the child to exit. By default, stdin, stdout and stderr are inherited from the parent.

Do parent and child process execute concurrently?

Father and child processes do run concurrently, and it is not predictable which process is running at what time. From a first inspection you have a loop that starts from the father process and creates 8 child processes, that on their hand each creates other child processes!

What is shared between parent and child process when one process creates another?

3.5 When a process creates a new process using the fork()operation, which of the following states is shared between the parent process and the child process? Answer: Only the shared memory segments are shared between the parent pro- cess and the newly forked child process.

How to get stdout in C?

In C, to print to STDOUT, you may do this: printf("%sn", your_str);


1 Answers

So you have a loop that creates several child processes. Each of these child processes will be using two pipes: read from previous and write to the next. To set up a pipe for the reading end you need to close the write end of the pipe, and dup2 the read end into the stdin. Similar for the pipe where the process will be writing.

void set_read(int* lpipe)
{
    dup2(lpipe[0], STDIN_FILENO);
    close(lpipe[0]); // we have a copy already, so close it
    close(lpipe[1]); // not using this end
}
  
void set_write(int* rpipe)
{
    dup2(rpipe[1], STDOUT_FILENO);
    close(rpipe[0]); // not using this end
    close(rpipe[1]); // we have a copy already, so close it
}

When you fork each children you need to attach the pipes to it.

void fork_and_chain(int* lpipe, int* rpipe)
{
    if(!fork())
    {
        if(lpipe) // there's a pipe from the previous process
            set_read(lpipe);
        // else you may want to redirect input from somewhere else for the start
        if(rpipe) // there's a pipe to the next process
            set_write(rpipe);
        // else you may want to redirect out to somewhere else for the end

        // blah do your stuff
        // and make sure the child process terminates in here
        // so it won't continue running the chaining code
    }
}

With this in hand you can now write a loop that continuously forks, attaches the pipes, and then reuses the output pipe as the input pipe for the next one. Of course, once both ends of a pipe have been connected to child processes, the parent should not leave it open for itself.

// This assumes there are at least two processes to be chained :)

// two pipes: one from the previous in the chain, one to the next in the chain
int lpipe[2], rpipe[2];

// create the first output pipe
pipe(rpipe);

// first child takes input from somewhere else
fork_and_chain(NULL, rpipe);

// output pipe becomes input for the next process.
lpipe[0] = rpipe[0];
lpipe[1] = rpipe[1];

// chain all but the first and last children
for(i = 1; i < N - 1; i++)
{
    pipe(rpipe); // make the next output pipe
    fork_and_chain(lpipe, rpipe);
    close(lpipe[0]); // both ends are attached, close them on parent
    close(lpipe[1]);
    lpipe[0] = rpipe[0]; // output pipe becomes input pipe
    lpipe[1] = rpipe[1];
}

// fork the last one, its output goes somewhere else      
fork_and_chain(lpipe, NULL);
close(lpipe[0]);
close(lpipe[1]);

The closing bits are very important! When you fork with an open pipe, there will be four open file descriptors: two on the parent process, and two others on the child process. You have to close all of those you won't be using. That's why the code above always closes the irrelevant ends of the pipes in the child processes, and both ends on the parent.

Also note that I am giving special treatment to the first and the last processes, because I don't know where the input for the chain will come from, and where the output will go to.

like image 153
R. Martinho Fernandes Avatar answered Nov 15 '22 21:11

R. Martinho Fernandes