Как выйти из простой проблемы производителя-потребителя

#c #posix #parallel-processing #producer-consumer

#c #posix #параллельная обработка #производитель-потребитель

Вопрос:

Я пытаюсь разработать простую программу производителя-потребителя. У меня есть этот код:

 //global variable g_lastImage is declared as:
volatile int g_lastImage = 0;

void producer(void) {
    int i = 0;
    while (1) {     
        sem_wait(amp;g_shm->PSem);
        printf("I:%dn",i);
        if (i == 5) {
            g_lastImage = 1;
            printf("It's time to say goodbye!n");
            sem_post(amp;g_shm->ChSem);
            return;
        }
        printf("producingn"); 
        i  ;
        sem_post(amp;g_shm->ChSem);
    }
}


void consumer(void) {
    while (1) {
        sem_wait(amp;g_shm->ChSem);
        if (g_lastImage) {
            printf("Bye!n");
            return;
        }
        printf("consumingn");
        sem_post(amp;g_shm->PSem);
    }
}

int main() {
    alloc(); /*allocates shared memory and two semaphores, 
                  ChSem on initial counter value 0 and PSem on value 1*/
    int processes = 1; //let's start with one process only just for now
    int id = 0, i = 0, status;

    for (i = 0; i < processes; i  ) {
        id = fork();
        if (id < 0) {
          perror ("errorn");
          exit(1);
        } else if (id == 0) {
          consumer();
          printf("child exitsn");
          exit(0);
        }
    }
    producer();

    for (i = 0; i < processes;   i) {
        wait(amp;status);
    }
    return 1;
}
  

К сожалению, этот код заканчивается взаимоблокировкой. У меня есть этот вывод:

 I:0
producing
consuming
I:1
producing
consuming
I:2
producing
consuming
I:3
producing
consuming
I:4
producing
consuming
I:5
It's time to say goodbye!
consuming
//deadlock - nothing written 
  

Пожалуйста, обратите внимание, что «Пока!» не написано. С другой стороны, дополнительное «потребление» есть. Что не так с этим решением? Использование глобальной переменной для определения конца не подходит? Не могу разобраться…

Спасибо за любые идеи.

РЕДАКТИРОВАТЬ: В соответствии с вашими советами я изменил выделение локальной переменной на volatile и добавил ‘ n’, но проблема сохраняется.

Комментарии:

1. Извините за эту глупую ошибку, эта напечатана, хотя проблема сохраняется.

Ответ №1:

Вы также должны поделиться своим флагом, это работает так, как вы ожидаете :

 #include <semaphore.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/mman.h>

struct Shared
{
    sem_t PSem ;
    sem_t ChSem ;
    int g_lastImage ;
} * g_shm ;

void producer(void) {
    int i = 0;
    while (1) {     
        sem_wait(amp;g_shm->PSem);
        printf("I:%dn",i);
        if (i == 5) {
            g_shm->g_lastImage = 1;
            printf("It's time to say goodbye!n");
            sem_post(amp;g_shm->ChSem);
            return;
        }
        printf("producingn"); 
        i  ;
        sem_post(amp;g_shm->ChSem);
    }
}


void consumer(void) {
    while (1) {
        sem_wait(amp;g_shm->ChSem);
        if (g_shm->g_lastImage) {
            printf("Bye!n");
            return;
        }
        printf("consumingn");
        sem_post(amp;g_shm->PSem);
    }
}

int main()
{
    g_shm = mmap( NULL , sizeof( struct Shared ) , PROT_READ | PROT_WRITE , MAP_SHARED | MAP_ANONYMOUS , -1 , 0 );
    sem_init( amp; g_shm->PSem , 1 , 1 );
    sem_init( amp; g_shm->ChSem , 1 , 0 );
    g_shm->g_lastImage = 0 ;

    int processes = 1;
    int id = 0, i = 0, status;

    for (i = 0; i < processes; i  )
    {
        id = fork();
        if (id < 0) {
          perror ("errorn");
          exit(1);
        } else if (id == 0) {
          consumer();
          printf("child exitsn");
          exit(0);
        }
    }
    producer();

    for (i = 0; i < processes;   i)
    {
        wait(amp;status);
    }
    return 1;
}
  

Комментарии:

1. Если бы я мог поставить сотню плюсов, я бы определенно поставил! Спасибо

Ответ №2:

volatile вам здесь не поможет, потому что вы разветвляете свои процессы. Это приведет к созданию копии g_lastImage и, следовательно, родительский процесс, который вызывает producer(), изменит свое собственное значение g_lastImage, тогда как дочерний процесс (который получает свою собственную копию этой переменной при fork) всегда будет иметь g_lastImage == 0, и, следовательно, вы окажетесь в тупике. Вы могли бы просто вставить выделение g_lastImage также в выделение ваших семафоров, поскольку кажется, что вы распределили их правильно, чтобы они были в других процессах 😉

Комментарии:

1. кстати, чтобы позволить ему работать с большим количеством процессов, мне придется публиковать ChSem столько раз, сколько у меня есть процессов, верно?