我试图更好地理解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'
,但随后,消费者就可以按预期只读取写入文件的最后一个字符。
有没有办法让它与等待语句一起使用?
答案 0 :(得分:0)
问题出在并发
我会说问题出在(缺乏)同步上。在生产者/消费者的安排中,生产者通常具有一种向消费者发出信号,告知有新商品可供消费的手段,而消费者在尝试消费该信号之前要等待该信号。那里的详细信息各不相同,但它们通常还包括生产者向消费者发出信号的通知,即将不再出售任何物品。
您的使用者不等待任何明确的信号,并且不使用可用的数据(文件长度)来确定有新商品可用。另一方面,它不努力在消耗的物品中保持自己的位置,因此,如果生产者领先,它很容易错过物品。而且,消费者忙碌的循环会执行不小的昂贵的I / O操作,这是解决此问题的非常昂贵的方法。
有没有办法让它与等待语句一起使用?
仅当您希望生产者在消费者消耗任何东西之前完成生产时。这就是wait()
的作用:它等待另一个进程终止。在这种情况下,您希望使用者只从头开始逐个字符地读取文件,而不是直接跳到结尾。
如果您希望生产者和消费者同时取得进展,那么最简单的方法是利用系统已经提供给您的功能,即使用FIFO或管道而不是常规文件。这样,生产者就可以一个接一个地写一个字符,而消费者可以一个接一个地读一个字符,而无需任何重新打开和重新定位的废话。
如果必须使用常规文件执行此操作,则可以使用一对信号量或互斥体+条件变量来使生产者和使用者轮流使用。另外,使用者可以通过多种方式监视文件以检测文件何时已更改(stat
/ fstat
,inotify
等),以避免不必要地尝试从文件中读取内容,您可以将其与它结合起来,以跟踪其在该文件中的位置,以免重新读取它已经消耗的数据。理想情况下,两个程序都不会多次打开文件,但是生产者可能需要在每次写入后fflush
。