Как мне использовать две трубы в Unix C?

У меня есть домашняя работа, которая говорит следующее:

Напишите программу на C, которая создает дочерний элемент, который также создаст дочерний элемент, создаст канал между тремя процессами, первый процесс (отец) соединит второй (дочерний элемент), а дочерний элемент соединится с третьим (дочерний элемент дочернего элемента).). Наша программа должна отображать общее количество пользователей системы, которые используют bash в качестве оболочки по умолчанию. Результат работы программы должен совпадать с "cat / etc / passwd | grep" / bin / bash $ "| wc-l"

Меня смущает первый ребенок и метод, которым мы закрываем первый канал и открываем второй одновременно. Если вы ответите мне с правильным кодом, я пойму это правильно один раз.

Спасибо.

Вот что я написал до сих пор:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
main()
{
int pid, pid2;
int fd[2];
int fd2[2];
char *arg[3];
char *arg2[3];
char *arg3[3];  
if (pipe(fd) == -1)
{
    perror("pipe");
    exit(1);
}
pid = fork();
if (pid == -1)
{
    perror("fork");
    exit(2);
}
if (pid == 0)
{
    if (pipe(fd2) == -1)
    {
        perror("pipe");
        exit(11);
    }
    pid2=fork();
    if(pid2 == -1)
    {
        perror("fork 2");
        exit(22);
    }
    if (pid2 == 0)
    {
        //i am child 2 (child of the child)
        close (fd2[1]);
        dup2 (fd2[0],0);
        close (fd2[0]);
        arg3[0] = "wc";
        arg3[1] = "-l";
        arg3[2] = NULL;
        execvp("wc", arg3);
        perror("execvp second child");
    }
    else
    {
        //i am child 1
        close (fd[1]);
        dup2(fd[0],0);
        close (fd[0]);
        close (fd2[0]);
        dup2(fd2[1],1);
        close (fd2[1]);
        arg2[0] = "grep";
        arg2[1] = "/bin/bash$";
        arg2[2] = NULL;
        execvp("grep", arg2);
        perror("execvp first child");
    }
}
else
{
    //i 'm the father
    close (fd[0]);
    dup2(fd[1],1);
    close (fd[1]);
    arg[0] = "cat";
    arg[1] = "/etc/passwd";
    arg[2] = NULL;
    execvp("cat", arg);
    perror("execvp father");    
}   

}

1 ответ

Решение

Ваша программа почти работает. Чего не хватает, так это

    //i am child 2 (child of the child)
    close (fd[1]);
    close (fd[0]);

Канал, который вы назвали fd, предназначен для связи между 'cat' и 'grep'. То, что происходит в вашем текущем коде, заключается в том, что cat выводит файл и закрывает его вывод. Grep читает все это и ожидает ввода EOF. Поскольку "child 2" по-прежнему имеет входную сторону канала открытой (она унаследовала его через fork), grep ждет вечно. Если запустить вашу программу, а затем введите ps Вы должны увидеть grep и wc, которые ждут, чтобы закончить.

Другая вещь, которую вы обычно делаете при построении конвейера, подобного этому, это организуйте его так, чтобы конечная задача (в данном случае wc) была той, которую ожидает оболочка. Как написано, когда ваша программа запускается из оболочки, она завершится, когда cat завершит работу, и выходные данные wc будут напечатаны, как будто из фоновой задачи. Если вы расположите канал так, чтобы wc находился под "i child 1", то оболочка будет ожидать wc вместо этого.

В качестве альтернативы вы можете отключить все три процесса, и "child 1" вызовет wait() ждать их всех перед выходом. Этот процесс ожидания будет похож на вашу крошечную оболочку.

Другие вопросы по тегам