1

我在使用 dup2 使 ac 程序执行诸如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;
}
4

1 回答 1

0

您没有关闭足够的文件描述符。

/* 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);
}

当修改为使用/usr/bin而不是 时/bin,该程序在 Mac OS X 10.7.3 上运行良好。它列出了三个文件,然后生成有关“在这里继续”的消息:

bzegrep
bzfgrep
bzgrep
Continuing here...
That's enough of that!
于 2012-02-27T04:16:07.543 回答