多管不起作用

时间:2016-04-27 21:16:50

标签: c linux pipe ipc pipeline

我需要实现这样的IPC模式:

runtime data -> filter1 -> filter2 -> output。 (与data | filter1 | filter2相同)。

我可以将数据传递给第一个过滤器,但是第二个我不能(可能因为在第一个孩子stdout fd没有关闭)。如何正确实现这样的架构?

P.S。 filter1和filter2只是从stdin读取并写入stdout。

我的代码:

int main() {
    int fd1[2];
    pipe(fd1);
    pid_t pid1;

    if ((pid1 = fork()) > 0) {
        char data[] = "Hello world!";

        close(fd1[0]);
        write(fd1[1], data, sizeof(data));
        close(fd1[1]);
        wait(NULL);
        exit(EXIT_SUCCESS);

    } else if (pid1 == 0) {
        int fd2[2];
        pipe(fd2);
        pid_t pid2;

        dup2(fd1[0], STDIN_FILENO);
        dup2(fd2[1], STDOUT_FILENO);
        close(fd1[0]); close(fd1[1]);
        close(fd2[0]); close(fd2[1]);

        if ((pid2 = fork()) > 0) {
            execl("./upcase", "upcase", NULL);
            perror("execl");
            exit(EXIT_FAILURE);
        } else if (pid2 == 0) {
            close(fd1[0]); close(fd1[1]);

            dup2(fd2[0], STDIN_FILENO);
            close(fd2[0]); close(fd2[1]);

            execl("./reverse", "reverse", NULL);
            perror("execl");
            exit(EXIT_FAILURE);
        } else {
            perror("pid2");
            exit(EXIT_FAILURE);
        }

    } else {
        perror("pid1");
        exit(EXIT_FAILURE);
    }

}

1 个答案:

答案 0 :(得分:1)

你太早关闭管道了。通常,在fd2[0]中使用之前,请关闭dup2。当您在第二个分叉之前重定向FILENO_STDOUT时,第二个过滤器不再能够访问原始标准输出。

以下代码有效:

int main() {
    int fd1[2];
    pipe(fd1);
    pid_t pid1;

    if ((pid1 = fork()) > 0) {
        char data[] = "Hello world!";

        close(fd1[0]); // OK, will no longer be used
        write(fd1[1], data, sizeof(data));
        close(fd1[1]);
        wait(NULL);
        exit(EXIT_SUCCESS);

    } else if (pid1 == 0) {
        int fd2[2];
        pipe(fd2);
        pid_t pid2;
        close(fd1[1]); // OK, no used from here

        if ((pid2 = fork()) > 0) {
        dup2(fd1[0], STDIN_FILENO);  // redirections for filter1
        dup2(fd2[1], STDOUT_FILENO);
        close(fd1[0]);               // close everything except stdin and stdout
        close(fd2[0]); close(fd2[1]);
            execl("./upcase", "upcase", NULL);
            perror("execl upcase");
            exit(EXIT_FAILURE);
        } else if (pid2 == 0) {
            close(fd1[0]);             // not used here

            dup2(fd2[0], STDIN_FILENO); // redirection for filter2
            close(fd2[0]); close(fd2[1]); // close all what remains

            execl("./reverse", "reverse", NULL);
            perror("execl reverse");
            exit(EXIT_FAILURE);
        } else {
            ...