阻塞管道,c,linux

阻塞管道,c,linux,c,linux,pipe,blocking,C,Linux,Pipe,Blocking,我有一个叫做消费者和生产者的项目。 在其中,我的主程序创建给定数量的消费者和生产者 通过命令行参数指定的子进程。/main\u生产商的数量\u消费者的数量\u。 每个生产者生成随机数目的随机可打印字符,将这些字符写入特定于进程的文件和主进程指定的管道。每个使用者从主进程指定给它的管道中读取所有字符,并将它们写入自己的进程特定文件。主程序完成后,生产者文件中的字符总数应与消费者文件中的字符总数相同 我有一个问题,如何告知消费者有关产品的结束。我尝试让生产者在数据后写一个空字符,但这并不能解决我的问

我有一个叫做消费者和生产者的项目。 在其中,我的主程序创建给定数量的消费者和生产者 通过命令行参数指定的子进程。/main\u生产商的数量\u消费者的数量\u。 每个生产者生成随机数目的随机可打印字符,将这些字符写入特定于进程的文件和主进程指定的管道。每个使用者从主进程指定给它的管道中读取所有字符,并将它们写入自己的进程特定文件。主程序完成后,生产者文件中的字符总数应与消费者文件中的字符总数相同

我有一个问题,如何告知消费者有关产品的结束。我尝试让生产者在数据后写一个空字符,但这并不能解决我的问题,因为当我创建的生产者多于消费者时,并非所有的产品都会被消费者读取,每个消费者在读取空字符时都会完成其工作。另一方面,当消费者的数量大于生产者的数量时,一些消费者永远不会读取空字符,因此永远不会完成

我认为我需要一种不同的机制来通知每个生产者的数据的结束,但我不知道如何通知消费者管道的结束。我读过一些关于fcntl的东西,但我不知道如何在代码中使用它

代码如下:

主要内容:


我如何向消费者发出数据结束的信号,以便他们中的消费者读取所有数据,并且所有人都能识别数据的结束?

您可能应该更仔细地思考如何解决这个问题。例如,如果其中一个生产商比其他生产商停止的时间早得多,那么应该停止其中一个消费者吗?如果没有,那么生产者不应该向消费者发送代码,只有主程序应该关心他们已经终止

我解决这个问题的方法是,消费者应该被主程序终止,而不是被制作人终止。最简单的方法是关闭管道的发送端。然后,读取端将获得文件的结尾,即读取返回的大小为0

在代码中,这可能意味着

1不从生产者发送0

2让主程序等待所有生产者首先终止,并在所有生产者都终止后关闭管道,然后再等待消费者

3使使用者在读取返回0时退出


还请注意,您的代码还有其他问题。例如,您不能通过execl传递指向整数的指针,只能传递字符串。

您使这变得比需要的更困难

消费者识别数据结尾的自然方式是作为管道上的文件结尾。他们每个人都会以读取返回0的形式看到这一点,这将发生在管道写入端的所有副本都已关闭且没有更多数据可从中读取之后。由于消费者和生产者都共享相同的管道,这也将在消费者之间提供一些自然的数据平衡

然而,请注意,我说过管道写入端的所有副本都必须关闭。这包括主程序中的副本,以及每个制作人和消费者中的副本。事实证明,您确实关闭了所有这些,但您依赖于终止制作人,以关闭其中每一个中的一个副本。这有点不干净,而且肯定是针对具体情况的。制作人在完成这些任务后明确地关闭它们,这将是一种更好的风格

此外,您的代码还显示了一些其他问题和奇怪之处,其中包括:

你对dup的使用毫无意义。既然您要将文件描述符编号传递给子级,那么您也可以让它们使用原始的管道端文件描述符。dup或更好的常用用法:在像您这样的环境中,dup2是使一个或多个特定的文件描述符成为要复制的文件描述符的副本。例如,那些标准流。请注意,如果您确实使用标准流,那么它们具有众所周知的文件描述符编号,因此您不需要告诉孩子们要使用哪些FD

execl的参数和每个进程argv的元素都是指向字符串的指针,因此类型为char*,以argc中未计算的该类型的空指针终止。您在execl调用中指定了int*类型的一些指针,并且您的子进程假定它们接收到该类型的指针。这可能是你碰巧遇到的情况,但这是不正确的,因为父母和孩子的行为都没有定义


您知道传递给程序的参数是字符串,即以null结尾的字节字符串吗?现在考虑如何将描述符传递给制作人程序t
hough execl,以及生产者程序如何解析该参数。当然,消费者程序也有同样的问题。为了绕过这个问题,请考虑生产者程序如何写入标准输出,消费者程序如何通过标准输入读取生产者输出。您只有一个管道。根据问题描述,我希望每个用户都有自己的管道。如果一个使用者从一个管道中读取所有数据,那么下一个使用者将没有剩余的数据可读取,因此您最好只有一个使用者。n=*argv[1]。。。雷登。。。几乎可以肯定,这并没有达到你的预期。也就是说,您对它的预期几乎肯定是错误的。您没有关闭足够的管道描述符。在子对象中复制描述符后,应该关闭管道的两端。不清楚你为什么要复制管道。如果管道从文件描述符3和4开始,则您的孩子都使用文件描述符5。execl调用中的&n仅在较小的endian(例如英特尔计算机)上工作。它会在一台小小的endian计算机上严重失败。它将control-E传递给孩子们。n=*argv[1];正确收集该数字。这是对C的一种非常古怪的滥用。我已经按照你的指示改正了所有的错误。一切都很好。非常感谢你的帮助。
int n;
int i,w,x;
int pipeT[2];
if(pipe(potok) != 0) exit(EXIT_FAILURE);
printf("[MAIN] Creating %d producers!\n", atoi(argv[1]));
for(i = 0; i < atoi(argv[1]); i++) {
  switch(fork()) {
      case -1:
          exit(3);
          break;
      case 0:
          if((n = dup(pipeT[1])) == -1) exit(5);
          close(pipeT[0]);
          if((execl("./producer","producer", &n, NULL)) == -1) exit(4);
          break;
      default:
          break;
  }
}
printf("[MAIN] Creating %d consumers!\n", atoi(argv[2]));
for(i = 0; i < atoi(argv[2]); i++) {
  switch(fork()) {
      case -1:
          exit(3);
          break;
      case 0: //Proces potomny
          if((n = dup(pipeT[0])) == -1) exit(5);
          close(pipeT[1]);
          if((execl("./consumer","consumer", &n, NULL)) == -1) exit(4);
          break;
      default:
          break;
  }
}
close(pipeT[0]);
close(pipeT[1]);
for (i = 0; i < atoi(argv[1]) + atoi(argv[2]); i++) {
    w = wait(&x);
    if (w == -1) exit(6);
}
int main(int argc, char *argv[]) {
  srand(getpid());
    int k,t,n;
  n = *argv[1];
    char sign;
    char nameOfFile[20];
    sprintf(nameOfFile, "P/p_%d", getpid());
    FILE* f = fopen(nameOfFile, "w");
  if(f == NULL) exit (1);
    int i;
  int numberOfSigns = rand()%100;
    for(i = 0; i < numberOfSigns; i++) {
        sign = rand()%94 + 32;
    if (write(n, &sign, sizeof(char)) == -1) exit(EXIT_FAILURE);
        fprintf(f, "%c", sign);
    }
  sign = 0;
  write(n, &sign, sizeof(char));
    fclose(f);
    return 0;
}
int main(int argc, char *argv[]) {
    char sign;
  char nameOfFile[20];
  int n = *argv[1];
    sprintf(nameOfFile, "K/k_%d", getpid());
    FILE* f = fopen(nameOfFile, "w");
  if(f == NULL) exit (1);
    do {
        if ((read(n, &sign, sizeof(char))) == -1) exit(EXIT_FAILURE);
        if(sign != 0) fprintf(f, "%c" , sign);
  } while(sign != 0);
    fclose(f);
    return 0;
}