Tomáš Vavro
Tomáš Vavro

Reputation: 67

pipe stdout of a child to stdin of another child in c

This is what I'm trying to do: a parent process creates two child processes, then pipes stdout of one to stdin of another. Then parent waits for 5 secs and kills the first child.

This is how I approached it: First I create a pipe. Then fork to create the first child (gen in code) and dup2 to duplicate pipe's write onto stdout. Another fork for second child (called cons in code), dup2 to duplicate read end onto stdin. Cons just prints the data. Parent sends SIGTERM to first child, second child reads until EOF, so it closes on it's own.

Nothing but my error output (here used for debugging) is printed. Gen generates two random numbers, but loop in cons doesn't get executed. So I suppose there's nothing on stdin of cons. I consulted Google and followed this How do I chain stdout in one child process to stdin in another child in C?, but didn't manage to figure out what I messed up. Would appreciate any help. Thanks

Compilation: gcc -std=c99 -Wall -Werror main.c -o main on Bash in Windows 10

Code:

#define _POSIX_SOURCE
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <signal.h>

#define READ_END 0
#define WRITE_END 1
#define BUF_SIZE 10

int main(int argc, char* argv[])
{
    pid_t gen, cons;
    int fd[2];

    if (pipe(fd) < 0) {
        // pipe error
        exit(1);
    }

    gen = fork();

    if (gen < 0) {
        // fork error
        close(fd[READ_END]);
        close(fd[WRITE_END]);
        exit(2);
    } else if (gen == 0) {
        // gen child
        close(fd[READ_END]);
        time_t t;
        srand((unsigned)time(&t));
        dup2(fd[WRITE_END], STDOUT_FILENO);
        close(fd[WRITE_END]);
        while(1) {
            int a = rand() % 1000;
            int b = rand() % 1000;
            printf("gen %d %d\n", a, b);
            fprintf(stderr, "err, gen %d %d\n", a, b);
            sleep(1);
        }
    }
    else {
        cons = fork();
        if (cons < 0) {
                // fork error
            close(fd[READ_END]);
            close(fd[WRITE_END]);
            kill(gen, SIGKILL);
            exit(2);
        } else if (cons == 0) {
            // cons child
            close(fd[WRITE_END]);
            dup2(fd[READ_END], STDIN_FILENO);
            close(fd[READ_END]);
            char line[BUF_SIZE];
            while (fgets(line, sizeof(line), stdin)) {
                printf("cons received: %s\n", line);
                fprintf(stderr, "cons lives!\n");
            }
        } else {
            // parent
            close(fd[READ_END]);
            close(fd[WRITE_END]);
            sleep(5);
            kill(gen, SIGTERM);
        }
    }
    return 0;
}

Upvotes: 2

Views: 1905

Answers (1)

Serge Ballesta
Serge Ballesta

Reputation: 148910

Standard output is by default buffered, so your gen child only queues output for later sending. So you must fflush it to force your messages to be immedialely delivered:

        ...
        printf("gen %d %d\n", a, b);
        fprintf(stderr, "err, gen %d %d\n", a, b);
        fflush(stdout);             // <= force immediate send
        sleep(1);
        ...

Upvotes: 1

Related Questions