Проблема с использованием dup2, чтобы заставить программу на C выполнить такую ​​команду, как 'ls / bin | grep grep | grep b ' - PullRequest
1 голос
/ 27 февраля 2012

У меня проблемы с использованием dup2, чтобы заставить программу переменного тока выполнить такую ​​команду, как ls /bin | grep grep | grep b.Когда я закомментирую третью команду и связанный с ней канал, он отлично выполняет ls /bin | grep grep, но с последней командой он просто сразу возвращается.Также, когда я ввожу 'ps', процессы все еще работают.Я думаю, это связано с тем, как я закрываю трубы.Мой код ниже:

int main()
{
    int pipeA[2];
    int pipeB[2];

    pipe(pipeA);
    pipe(pipeB);

    int pidA,pidB,pidC;

    if(pidA = fork())
    {
            close(pipeA[0]);
            dup2(pipeA[1],1);
            close(pipeA[1]);
            execlp("ls","ls","/bin",NULL);
            printf("error\n");
    }

    if(pidB = fork())
    {
            close(pipeA[1]);
            dup2(pipeA[0],0);
            close(pipeA[0]);

            close(pipeB[0]);
            dup2(pipeB[1],1);
            close(pipeB[1]);
            execlp("grep","grep","grep",NULL);
            printf("error\n");
    }

    if(pidC = fork())
    {
            close(pipeB[1]);
            dup2(pipeB[0],0);
            close(pipeB[0]);
            execlp("grep","grep","b",NULL);
            printf("error");
    }


    while(pidA != wait(0)){}

    return 0;
}

1 Ответ

0 голосов
/ 27 февраля 2012

Вы закрываете недостаточно файловых дескрипторов.

/* Semi-working code */
int main()
{
    int pipeA[2];
    int pipeB[2];

    pipe(pipeA);
    pipe(pipeB);

    int pidA,pidB,pidC;

    if (pidA = fork())
    {
            close(pipeB[0]);  // "ls" is not going to use the second pipe
            close(pipeB[1]);  // Ditto
            close(pipeA[0]);
            dup2(pipeA[1], 1);
            close(pipeA[1]);
            execlp("ls", "ls", "/bin", (char *)NULL);
            fprintf(stderr, "error executing 'ls'\n");
            exit(1);
    }

    if (pidB = fork())
    {
            close(pipeA[1]);
            dup2(pipeA[0],0);
            close(pipeA[0]);
            close(pipeB[0]);
            dup2(pipeB[1],1);
            close(pipeB[1]);
            execlp("grep", "grep", "grep", (char *)NULL);
            fprintf(stderr, "error execing 'grep grep'\n");
            exit(1);
    }

    if (pidC = fork())
    {
            close(pipeA[0]);  // The second grep is not going to use the first pipe
            close(pipeA[1]);  // Ditto
            close(pipeB[1]);
            dup2(pipeB[0],0);
            close(pipeB[0]);
            execlp("grep", "grep", "b", (char *)NULL);
            fprintf(stderr, "error execing 'grep b'\n");
            exit(1);
    }

    close(pipeA[0]);  // The parent process is not using the pipes at all
    close(pipeA[1]);
    close(pipeB[0]);
    close(pipeB[1]);

    while (pidA != wait(0))
        ;

    return 0; 
}

Поскольку вы не закрыли pipeA во втором grep, вы получите первый grep, ожидающий ввода из канала, второй grep по-прежнему открыт, даже если процесс не запишет к этому. Из-за этого первый grep не заканчивается, поэтому второй также не заканчивается - даже если ls завершается. Эти комментарии будут применяться, даже если родительский процесс закрыл свои копии каналов - как исправленный код.

Обратите внимание, как вы закрываете все 4 дескриптора, возвращаемых двумя вызовами pipe() в каждом из четырех процессов - три дочерних и родительский процесс.

Это оставляет одну остаточную проблему - иерархия процессов перевернута из-за вашего обычного использования if (pidA = fork()). У вас есть дочерний процесс, ожидающий своих родителей. Вам необходимо использовать:

if ((pidA = fork()) == 0)
{
    /* Be childish */
}

Аналогично для каждого из двух других процессов. Вы также должны проверить pipe() вызовы и fork() вызовы на отказ, просто чтобы быть уверенным.

#include <stdio.h>
#include <unistd.h>
#include <stdarg.h>
#include <sys/wait.h>
#include <stdlib.h>

static void err_exit(const char *format, ...);

/* Working code */
int main(void)
{
    int pipeA[2];
    int pipeB[2];

    if (pipe(pipeA) != 0 || pipe(pipeB) != 0)
        err_exit("Failed to create a pipe\n");

    int pidA,pidB,pidC;

    if ((pidA = fork()) < 0)
        err_exit("Failed to fork (A)\n");
    else if (pidA == 0)
    {
            close(pipeB[0]);  // "ls" is not going to use the second pipe
            close(pipeB[1]);  // Ditto
            close(pipeA[0]);
            dup2(pipeA[1], 1);
            close(pipeA[1]);
            execlp("ls", "ls", "/bin", (char *)NULL);
            err_exit("error executing 'ls'\n");
    }

    if ((pidB = fork()) < 0)
        err_exit("failed to fork (B)\n");
    else if (pidB == 0)
    {
            close(pipeA[1]);
            dup2(pipeA[0],0);
            close(pipeA[0]);
            close(pipeB[0]);
            dup2(pipeB[1],1);
            close(pipeB[1]);
            execlp("grep", "grep", "grep", (char *)NULL);
            err_exit("error execing 'grep grep'\n");
    }

    if ((pidC = fork()) < 0)
        err_exit("failed to fork (C)\n");
    else if (pidC == 0)
    {
            close(pipeA[0]);  // The second grep is not going to use the first pipe
            close(pipeA[1]);  // Ditto
            close(pipeB[1]);
            dup2(pipeB[0],0);
            close(pipeB[0]);
            execlp("grep", "grep", "b", (char *)NULL);
            err_exit("error execing 'grep b'\n");
    }

    close(pipeA[0]);  // The parent process is not using the pipes at all
    close(pipeA[1]);
    close(pipeB[0]);
    close(pipeB[1]);

    while (wait(0) != -1)
        ;

    printf("Continuing here...\n");
    sleep(3);
    printf("That's enough of that!\n");

    return 0; 
}

static void err_exit(const char *format, ...)
{
    va_list args;
    va_start(args, format);
    vfprintf(stderr, format, args);
    va_end(args);
    exit(1);
}

Эта программа работает нормально в Mac OS X 10.7.3, если ее использовать /usr/bin вместо /bin. В нем перечислены три файла, а затем генерируется сообщение «Продолжение здесь»:

bzegrep
bzfgrep
bzgrep
Continuing here...
That's enough of that!
...