生产者-消费者问题中的无限循环

时间:2019-04-30 14:37:05

标签: c fork producer-consumer

我试图更好地理解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',但随后,消费者就可以按预期只读取写入文件的最后一个字符。

有没有办法让它与等待语句一起使用?

1 个答案:

答案 0 :(得分:0)

  

问题出在并发

我会说问题出在(缺乏)同步上。在生产者/消费者的安排中,生产者通常具有一种向消费者发出信号,告知有新商品可供消费的手段,而消费者在尝试消费该信号之前要等待该信号。那里的详细信息各不相同,但它们通常还包括生产者向消费者发出信号的通知,即将不再出售任何物品。

您的使用者不等待任何明确的信号,并且不使用可用的数据(文件长度)来确定有新商品可用。另一方面,它不努力在消耗的物品中保持自己的位置,因此,如果生产者领先,它很容易错过物品。而且,消费者忙碌的循环会执行不小的昂贵的I / O操作,这是解决此问题的非常昂贵的方法。

  

有没有办法让它与等待语句一起使用?

仅当您希望生产者在消费者消耗任何东西之前完成生产时。这就是wait()的作用:它等待另一个进程终止。在这种情况下,您希望使用者只从头开始逐个字符地读取文件,而不是直接跳到结尾。

如果您希望生产者和消费者同时取得进展,那么最简单的方法是利用系统已经提供给您的功能,即使用FIFO或管道而不是常规文件。这样,生产者就可以一个接一个地写一个字符,而消费者可以一个接一个地读一个字符,而无需任何重新打开和重新定位的废话。

如果必须使用常规文件执行此操作,则可以使用一对信号量或互斥体+条件变量来使生产者和使用者轮流使用。另外,使用者可以通过多种方式监视文件以检测文件何时已更改(stat / fstatinotify等),以避免不必要地尝试从文件中读取内容,您可以将其与它结合起来,以跟踪其在该文件中的位置,以免重新读取它已经消耗的数据。理想情况下,两个程序都不会多次打开文件,但是生产者可能需要在每次写入后fflush