我试图在fork()
编程中更好地理解c
和并发性。我是新手,我无法理解逻辑。我尝试使用fork()
制作一个简单的生产者 - 消费者计划。基本上,producer()
函数应该从stdin
获取一个字符,并将其写入文件。同时,第二个进程运行consumer
代码,该代码应该读取文件中的最后一个字符并将其回显到屏幕。 producer()
和consumer()
函数本身工作正常,即它们正在做各自应该做的事情,但问题在于并发性。这是我的代码:
#include<stdio.h>
#include <stdlib.h>
#include <unistd.h>
FILE* fp;
//char c;
void producer(){
char c=' ';
while(c!='x'){
puts("enter a char");
c = getchar();
while((fp = fopen("shared.txt", "at"))==NULL); //while the file is in use by another program
fputc(c,fp);
if(c!='\n')puts("file written to successfully");
fclose(fp);
}
return;
}
char readChar(){
char c;
while((fp = fopen("shared.txt", "rt"))==NULL);
fseek(fp, -1, SEEK_END);
c = fgetc(fp);
fclose(fp);
return c;
}
void consumer(){
char c;
do{
c = readChar();
printf("This is the latest character supplied: %c\n", c);
}while(c!='x');
}
int main(){
int pid = fork(); //now we fork processes
if(pid ==0 ){
producer(); //the child process should run and create some text in the file
}else{
wait(); consumer();
}
}
我在各自的分支机构调用producer()
和consumer()
之后尝试添加等待语句,但基本上无论如何,程序都无法按我的意愿行事。如果在main ()
我有
int main(){
int pid = fork(); //now we fork processes
if(pid ==0 ){
producer(); //the child process should run and create some text in the file
}else{
consumer();
}
}
我陷入无限循环。在一个或两个分支中的函数调用之后添加wait();
没有帮助,因为在控制传递给wait()
之前发生无限循环。
如果我试试这个:
int main(){
int pid = fork(); //now we fork processes
if(pid ==0 ){
producer(); //the child process should run and create some text in the file
}else{
wait(); consumer();
}
}
我可以从stdin
输入文本,直到我输入'x'
,然后按预期消费者只读取写入文件的最后一个字符。
有没有办法让它与wait语句一起使用?
问题在于并发性
我会说问题在于(缺乏)同步。在生产者/消费者安排中,生产者通常具有向消费者发信号通知新物品可供消费的手段,并且消费者在尝试消费之前等待该信号。细节因此而有所不同,但它们通常还包括一种方式,让生产者向消费者发出信号,告知不再有物品即将到来。
您的消费者不会等待任何明确的信号,并且它不会使用可用的数据(文件长度)来确定新项目是否可用。另一方面,它没有努力在所消耗的物品中保持自己的位置,因此如果生产者领先它,它很容易错过物品。此外,消费者忙碌循环,执行昂贵的I / O操作不会少,这是一个非常昂贵的方式来解决这个问题。
有没有办法让它与wait语句一起使用?
只有当您希望生产者在消费者消费任何东西之前运行完成时。这就是wait()
所做的:它等待另一个进程终止。在这种情况下,您希望消费者只是逐个字符地从头开始读取文件,而不是直接跳到最后。
如果您希望生产者和消费者同时取得进展,那么最简单的方法就是利用系统已经提供的设施,使用FIFO或管道而不是常规文件。然后制作人可以只写字符,消费者可以只读字符,而不会重新打开和重新定位废话。
如果你必须使用常规文件,那么你可以使用一对信号量或互斥+条件变量来让生产者和消费者轮流使用。或者,消费者可以通过各种方式监控文件以检测文件何时发生变化(stat
/ fstat
,inotify
等)以避免不必要地尝试从中读取文件,并且您可以将其与其结合以跟踪其自身的位置。该文件,以便不重新读取它已经消耗的数据。理想情况下,两个程序都不会多次打开文件,但生成器可能需要在每次写入后使用fflush
。