【问题标题】:Pipes between more than 2 children fail - C超过 2 个孩子之间的管道发生故障 - C
【发布时间】:2016-06-22 17:00:50
【问题描述】:

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

我使用这个命令:

./function nn 的孩子数。

父亲制作n 管道和n 孩子。

然后孩子们关闭他们不会使用的管道。

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

当我只使用 1 个孩子时,它可以完美运行。当我尝试使用 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);
}

编辑:我发布了对我有用的代码

【问题讨论】:

  • 请修正缩进。有经验的程序员通常更喜欢使用适当的缩进,因为它有助于直观地识别控制流和变量范围。您正在寻求帮助,因此尽您所能让他人更容易帮助您是有意义的。
  • 我尽了最大努力,但是当我在这里发布代码时,我必须手动放置 4 个空格,以便网络像代码一样识别它,并且缩进变得疯狂。我想知道是否有办法像代码一样标记部分文本,并且当我从文件中复制它时,缩进保持不变。
  • 选择您的代码并按编辑工具栏中的“{}”按钮(或根据工具提示,按 ctrl+K)。
  • 嘿,非常感谢。我已经在这里做了几个问题,但不知道如何解决这个问题,所以从现在开始我会做对的:)

标签: c pipe fork


【解决方案1】:

你有几个问题。

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

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

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

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

  • 父级应该关闭每个未使用的管道末端一次,但是您可以让每个分叉的子级关闭它们一次。将其移出循环。

  • 虽然 C 允许,但允许控制到达 main() 的右括号是一种糟糕的形式。请改用return 语句或调用exit()

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

  • 前面暗示您需要在进程之间进行通信,以便在任何一条消息中读取多少字节。您可以使用终止符(例如换行符或空字节)来做到这一点,或者首先发送一个(固定大小)整数来表示同一条消息中有多少个字符。

【讨论】:

  • 嘿,非常感谢您的回答。现在我有点困惑。我这样做for(制造孩子的人)的想法是变量i被复制到孩子的记忆中,所以我可以用它来识别它是什么孩子,并在我读/写时使用它在管道中(例如pp[i][1])。我想父亲只用if(i==0) 关闭管道,对吗?我也在使用for,所以我可以创建所有的孩子。
  • 我不建议摆脱创建孩子的for 循环。我建议移动关闭父级不需要的所有管道末端的代码。 if (i == 0) 当然是 close(pp[0][0]) 的条件,但仅此而已。 j 上的内部循环针对每个 i 执行。由于只有父级退出循环,因此在循环外简单地处理父级的管道末端会更干净,更不容易出错。
  • 是的,你是对的,只是移出那部分代码,工作正常 :) 谢谢
猜你喜欢
  • 2017-08-26
  • 1970-01-01
  • 1970-01-01
  • 2015-01-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多