如何退出简单的生产者 - 消费者问题

时间:2011-04-14 07:51:35

标签: c posix parallel-processing producer-consumer

我正在尝试制定一个简单的生产者 - 消费者计划。我有这段代码:

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

请注意“再见!”不是写的。另一方面,额外的“消费”是。这个解决方案有什么问题?使用全局变量检测结束不行吗?无法弄清楚......

感谢您的任何想法。

修改 根据您的建议,我将局部变量的分配更改为volatile并添加'\ n',但问题仍然存在。

2 个答案:

答案 0 :(得分: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;
}

答案 1 :(得分:1)

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