бесконечный цикл в задаче производитель-потребитель - PullRequest
0 голосов
/ 30 апреля 2019

Я пытаюсь лучше понять 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 голосов
/ 30 апреля 2019

проблема в параллелизме

Я бы сказал, что проблема в (отсутствии) синхронизации.В соглашении «производитель / потребитель» производитель обычно имеет средство для того, чтобы сигнализировать потребителю, что новый предмет доступен для потребления, и потребитель ждет этого сигнала, прежде чем пытаться его использовать.Подробности варьируются оттуда, но, как правило, они также включают способ, позволяющий производителю сообщить потребителю о том, что больше товаров не будет.

Ваш потребитель не ожидает какого-либо явного сигнала и не использует данныедоступно для него (длина файла), чтобы определить, что новый элемент доступен.С другой стороны, он не прилагает усилий, чтобы сохранить свое место среди потребляемых предметов, поэтому он может легко пропустить предметы, если производитель опередит их.Более того, потребитель занят циклами, выполняющими не менее дорогие операции ввода-вывода, что является очень дорогостоящим способом решения этой проблемы.

Есть ли способ заставить это работать с операторами ожидания?

Только если вы хотите, чтобы производитель работал до завершения, прежде чем потребитель что-либо потребит.Вот что делает wait(): он ждет, пока другой процесс не завершит .В этом случае вы бы хотели, чтобы потребитель просто читал файл с начала, символ за символом, а не прыгал прямо до конца.

Если вы хотите, чтобы производитель и потребитель делали прогресс одновременно, тогда самый простойДля этого нужно использовать средства, уже предоставленные вам системой, используя FIFO или канал вместо обычного файла.Тогда производитель мог бы просто писать символ за символом, а потребитель мог просто читать символ за символом, без всякой ерунды повторного открытия и изменения положения.

Если вы должны сделать это с обычным файлом, то вы можете использовать парусемафоров или условной переменной mutex +, чтобы заставить производителя и потребителя сменяться.Альтернативно, есть различные способы, которыми потребитель может отслеживать файл, чтобы определить, когда он изменился (stat / fstat, inotify и т. Д.), Чтобы избежать ненужных попыток чтения из него, и вы можете комбинировать это сон отслеживает свою позицию в этом файле, чтобы не перечитывать данные, которые он уже использовал.В идеале ни одна из программ не открывала файл более одного раза, но производителю может потребоваться fflush после каждой записи.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...