4

I am trying to work out a simple producer-consumer program. I have this code:

//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;
}

Unfortunately this code ends with deadlock. I have this output:

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 

Please notice that "Bye!" is not written. On the other hand extra "consuming" is. What is wrong with this solution? Using global variable for detecting the end is not ok? Can't figure it out...

Thank you for any ideas.

EDIT: Acording to your advices I changed the allocation of local variable to volatile and added the '\n' but the problem persists.

4

2 回答 2

3

你也必须分享你的旗帜,这正如你所期望的那样工作:

#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;
}
于 2011-04-14T08:21:56.573 回答
1

volatile 在这里帮不了你,因为你分叉了你的进程。这将导致 g_lastImage 的副本,因此调用 producer() 的父进程将更改其自己的 g_lastImage 值,而子进程(在 fork 中获取该变量的自己的副本)将始终具有 g_lastImage == 0,因此你最终陷入僵局。您也可以将 g_lastImage 的分配插入到信号量的分配中,因为您似乎正确分配了它们以将它们放在 poth 进程中;)

于 2011-04-14T09:30:22.470 回答