конвейерный вывод одного дочернего элемента на стандартный ввод другого дочернего элемента в c

Это то, что я пытаюсь сделать: родительский процесс создает два дочерних процесса, а затем передает стандартный вывод одного в стандартный ввод другого. Затем родитель ждет 5 секунд и убивает первого ребенка.

Вот как я подошел к этому: сначала я создаю трубу. Затем fork для создания первого дочернего элемента (генерация в коде) и dup2 для дублирования записи канала в stdout. Еще одна вилка для второго дочернего элемента (называемая cons в коде), dup2, чтобы дублировать конец чтения на stdin. Минусы просто выводят данные. Родитель отправляет SIGTERM первому дочернему элементу, второй ребенок читает до EOF, поэтому закрывается сам.

Ничего, кроме моих сообщений об ошибках (здесь используется для отладки), не печатается. Gen генерирует два случайных числа, но цикл cons не выполняется. Так что я полагаю, что на стандартном вводе минусов нет ничего. Я проконсультировался с Google и следил за этим Как связать stdout в одном дочернем процессе с stdin в другом дочернем процессе в C?, но не смог понять, что я напутал. Был бы признателен за любую помощь. Спасибо

Компиляция: gcc -std=c99 -Wall -Werror main.c -o main на Bash в Windows 10

Код:

#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;
}

person Tomáš Vavro    schedule 21.11.2017    source источник


Ответы (1)


Стандартный вывод по умолчанию буферизирован, поэтому ваш потомок поколения ставит в очередь вывод только для последующей отправки. Таким образом, вы должны fflush это, чтобы ваши сообщения были доставлены немедленно:

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