超过2个孩子之间的管道失败 - C

时间:2016-06-22 17:00:51

标签: c pipe fork

如何在3个或更多孩子之间制作功能性管道?

我使用这个命令:

./function n n子女数量。

父亲制造了n个管子和n个孩子。

之后,孩子们关闭了他们不会使用的管道。

然后父亲在第一个管道中写入内容,第一个孩子读取它,并将其写入下一个管道。最后一个孩子应该在stdout

中写下内容

当我只使用一个孩子时,它完美无缺。当我尝试使用2个孩子时,最后一个从管道中读取:-1个字符,当我尝试使用3个孩子时,我发现了段违规,代码无效。

希望你能帮助我,这是代码。

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

void use_pipes(int i);
void write_father(void);

int (*pp)[2];
int childrens;

int main(int argc, char* argv[]) {

    childrens = atoi(argv[1]);
    int p, i, j, aux;

    printf("I'm the parent and i'm making %d childrens\n", childrens);
    pp = malloc(sizeof (*pp) * childrens);
    for (i = 0; i < childrens; i++) {

        if (pipe(pp[i]) < 0) {
            perror("Error in pipe()");
            exit(1);
        }

    }//for

    for (i = 0; i < childrens; i++) {
        printf("I'm the parent pid: %d and I'm going to make the child nº: %d\n", getpid(), i);
        p = fork();

        switch (p) {
            case -1:
                printf("We couldn't make the child nº:%d\n", i);
                exit(1);
            case 0:
                //printf("I'm nº: %d, and I start my code\n",i);

                for (aux = 0; aux < childrens; aux++) {
                    if (aux == i) {
                        //printf("I'm the children nº: %d and I'm going to close the pipe[%d] of writing\n", i,i);
                        close(pp[i][1]);
                    } else if (aux == i + 1) {
                        //printf("I'm the children nº: %d and I'm going to close the pipe[%d] of reading\n", i,aux);
                        close(pp[aux][0]);
                    } else {
                        //printf("I'm the children nº: %d and I'm going to close the pipe[%d]\n", i,aux);
                        close(pp[aux][0]);
                        close(pp[aux][1]);
                    }
                }//for

                //printf("I finished to close my unused pipes\n");
                use_pipes(i);
                exit(0);

            default:
                break;
        }//switch
    }//for of fork
    close(pp[0][0]);
    for (j = 1; j < childrens; j++) {
        close(pp[j][0]);
        close(pp[j][1]);

    }//for
    write_father();
    int status;
    for (i = 0; i < childrens; i++) {
        wait(&status);
    }

}//main

void write_father() {
    int wroten;
    char buffer[50] = "Hello World";
    int len = strlen(buffer);
    wroten = write(pp[0][1], buffer, len);
    printf("The parent wrote: %d characters\n", wroten);
}

void use_pipes(int n_children) {
    int readed;
    char buffer [50];
    readed = read(pp[n_children][0], buffer, sizeof (buffer));
    printf("Children %d readed from pipe[%d][0]: %d characters\n", n_children, n_children, readed);
    if (n_children != childrens - 1) {
        printf("Children %d write in the pipe[%d][1]: %d characters\n", n_children, n_children + 1, readed);
        write(pp[n_children + 1][1], buffer, readed);
    } else
        write(1, buffer, readed);
}

编辑:我发布了适用于我的代码

1 个答案:

答案 0 :(得分:1)

你有几个问题。

  • int* pp[2]并不代表您认为的含义。这是一个指向int的两个指针的数组,但您看起来想要的是一个指向两个int数组的指针。那将是int (*pp)[2]。您的分段错误可能与此有关。

  • 更正了pp的类型,接下来必须正确分配;特别是,所有在一个块。这是实现这一目标的最简洁方法(请注意,不涉及循环,并且所需大小是根据指针的目标大小定义的):

    pp = malloc(childrens * sizeof(*pp));

如果您希望父级提前创建所有管道,那么您需要使用循环。

  • 父母应该每次关闭未使用的管道末端,但是每个孩子分叉时它会关闭它们一次。将其移出循环。

  • 虽然C允许,但允许控件到达main()的右括号是不好的形式。请使用return语句或致电exit()

  • 您认为您的I / O不会拆分数据,因此单write()read()次呼叫就足够了。这可能对你有用,但实际上并不可靠。您应该循环write()read()以在必要时通过多次调用传输完整的字节数。使用这些函数的返回值来帮助解决这个问题。

  • 前面提到您需要在进程之间进行通信,在任何一条消息中要读取多少字节。您可以使用终止符(例如换行符或空字节)执行此操作,或者首先发送一个(固定大小)整数,该整数表示同一消息中包含多少个字符。