Loki Astari
Loki Astari

Reputation: 264381

Forking a piped sub processes

What is the best technique to fork a pipe-lined sub processes?

My current program needs to run another processes that is actually a couple of commands linked by pipes. I do not need to know the output of the commands just if they fail or succeed so I am using fork/exec.

The equivalent on the command line would be

 /path/to/A arg1 arg2 | /path/to/B argB1 | /path/to/C

Note: Using a script is not practical as it A/B/C may change in the future.

The two techniques I though of are:

  1. Recursive fork. Connect the parent (input to its parent) output available for child in next fork.

  2. Create all pipes at top level.
    Then use a loop to fork all children that can then connect the pipes appropriately.

Upvotes: 3

Views: 346

Answers (2)

Don't fork recursively. Making B a subprocess of A is not a good idea. For example, if B calls setsid to run in its own session, it would take the unrelated A with it. If B dies, A would get a SIGCHILD, not you. In particular, you would not be able to obtain the return status of B.

Here's a sketch of the code to fork n children on a series of pipes. Warning: I typed the code directly into my browser; there are probably many typos, and I omitted all error checks.

char *executables[n];
char *args[n];
int pipes[2*n+2]; /* child i reads from  */
int child_pids[n];
int ret; /*Error checking omitted; abort if ret ever becomes negative*/
ret = pipe(pipes);
for (i = 0; i < n; i++) {
    ret = pipe(pipes + 2 * i + 2);
    ret = fork();
    if (ret == 0) {
        /* Code of child i */
        close(pipes[2*i+1]);
        close(pipes[2*i+2]);
        dup2(pipes[2*i], 0);
        dup2(pipes[2*i+3], 1);
        ret = execv(executables[i], args[i]);
    }
    close(pipes[2*i]);
    close(pipes[2*i+3]);
    child_pids[i] = ret;
}
/* interact with the subprocesses, then call wait or waitpid as needed */

Upvotes: 1

Andy Ross
Andy Ross

Reputation: 12033

If you're on a unix, a simple system("/path/to/A arg1 arg2 | /path/to/B argB1 | /path/to/C") will do what you want. It invokes a shell as /bin/sh -c $STRING_PASSED_TO_SYSTEM. If you want finer control, for example the ability to read the output or write to the input, consider the popen() routine in the C library.

Upvotes: 0

Related Questions