Как мне использовать две трубы в Unix C? - PullRequest
0 голосов
/ 30 октября 2010

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

Напишите программу на 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 Ответ

3 голосов
/ 30 октября 2010

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

    //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 вместо этого.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...