Как выйти из простой проблемы «производитель-потребитель» - PullRequest
4 голосов
/ 14 апреля 2011

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

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

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


void consumer(void) {
    while (1) {
        sem_wait(&g_shm->ChSem);
        if (g_lastImage) {
            printf("Bye!\n");
            return;
        }
        printf("consuming\n");
        sem_post(&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 ("error\n");
          exit(1);
        } else if (id == 0) {
          consumer();
          printf("child exits\n");
          exit(0);
        }
    }
    producer();

    for (i = 0; i < processes; ++i) {
        wait(&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 

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

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

EDIT: Согласно вашим советам, я изменил распределение локальной переменной на volatile и добавил '\ n', но проблема сохраняется.

Ответы [ 2 ]

3 голосов
/ 14 апреля 2011

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

#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(&g_shm->PSem);
        printf("I:%d\n",i);
        if (i == 5) {
            g_shm->g_lastImage = 1;
            printf("It's time to say goodbye!\n");
            sem_post(&g_shm->ChSem);
            return;
        }
        printf("producing\n"); 
        i++;
        sem_post(&g_shm->ChSem);
    }
}


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

int main()
{
    g_shm = mmap( NULL , sizeof( struct Shared ) , PROT_READ | PROT_WRITE , MAP_SHARED | MAP_ANONYMOUS , -1 , 0 );
    sem_init( & g_shm->PSem , 1 , 1 );
    sem_init( & 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 ("error\n");
          exit(1);
        } else if (id == 0) {
          consumer();
          printf("child exits\n");
          exit(0);
        }
    }
    producer();

    for (i = 0; i < processes; ++i)
    {
        wait(&status);
    }
    return 1;
}
1 голос
/ 14 апреля 2011

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

...