【发布时间】:2018-01-13 15:59:52
【问题描述】:
我有一个名为“消费者和生产者”的项目。
在其中,我的主程序创建给定数量的消费者和生产者
子进程,通过命令行参数 (./main number_of_producents number_of_consumers) 指定。
每个生产者生成随机数量的随机可打印字符,将它们写入特定于进程的文件和主进程指定的管道。每个消费者从主进程指定给它的管道中读取所有字符,并将它们写入自己的进程特定文件。主程序完成后,生产者文件中的字符组合数应与消费者文件中的字符组合数相同。
我对如何告知消费者产品停产有疑问。我试图通过让生产者每个人在他们的数据后写一个空字符来做到这一点,但这并不能解决我的问题,因为当我创建的生产者多于消费者时,并非所有产品都会被消费者读取(每个都完成它的当它读取一个空字符时工作)。另一方面,当消费者的数量大于生产者的数量时,一些消费者永远不会读取空字符,因此永远不会读完。
我认为我需要一种不同的机制来发出每个生产者数据结束的信号,但我不知道如何通知消费者管道结束。我读过一些关于fcntl 的文章,但我不知道如何在我的代码中使用它。
代码如下:
主要:
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;
}
如何向消费者发出数据结束的信号,以使其中的消费者读取所有数据并全部识别结束?
【问题讨论】:
-
您知道传递给程序的参数是字符串(即以空字符结尾的字节字符串)吗?现在考虑如何通过
execl将描述符传递给生产者程序,以及生产者程序如何“解析”该参数。当然,消费者计划也存在同样的问题。 -
作为绕过该问题的一种方法,请考虑生产者程序如何可能写入标准输出,而消费者程序如何通过标准输入读取生产者输出.
-
你只有一根管子。从问题描述来看,我希望每个消费者都有自己的管道。如果一个消费者从管道中读取所有数据,那么下一个消费者将没有任何可读取的内容,因此您还不如只有一个消费者。
-
n=*argv[1]; ... read(n, ...)几乎可以肯定不会达到您的预期。 (也就是说,你对它所做的事情的期望几乎肯定是错误的。) -
您没有关闭足够多的管道描述符。在您
dup子项中的描述符之后,您应该关闭管道的 both 端。目前尚不清楚为什么要复制管道。如果管道从文件描述符 3 和 4 开始,则您的孩子都使用文件描述符 5。您在execl()调用中的&n仅在小端(例如 Intel)计算机上巧合。在小端计算机上它会严重失败。它将 control-E 传递给孩子。n = *argv[1];正确收集了该号码。这是对 C 的非常古怪的滥用。