生产者消费者信号量值不正确

时间:2017-12-05 23:55:46

标签: c process semaphore producer-consumer

我尝试使用流程和System V IPC在C中实现生产者 - 消费者问题,而且我只是坚持一件事。这是我的代码的早期版本(没有实现队列操作,甚至是循环中的生产者和消费者执行),我用它来学习和测试信号量的工作方式:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <errno.h>
#include <time.h>
#include "sem.h"
#include "shm.h"

#define BUFFER_SIZE 9

int full;
int empty;
int mutex;

struct buff {
    int queue[BUFFER_SIZE];
} *buffer;

void producer();
void consumer();

int main() {

    int parent_pid, pid, i; 

    parent_pid = getpid();

    int shmid = allocate_shared_memory(sizeof(*buffer));         
    buffer = (struct buff *) attach_shared_memory(shmid);

    for (i = 0; i < BUFFER_SIZE; i++) {
        buffer->queue[i] = 0;
    }

    full = sem_allocate();
    empty = sem_allocate();
    mutex = sem_allocate();


    printf("Full %d\n", full);
    printf("Empty %d\n", empty);
    printf("Mutex %d\n", mutex);


    sem_init(full, 0);
    sem_init(empty, BUFFER_SIZE);
    sem_init(mutex, 1);


    printf("Full value %d\n", sem_get_val(full));
    printf("Empty value %d\n", sem_get_val(empty));
    printf("Mutex value %d\n", sem_get_val(mutex));


    srand(time(0));

    pid = fork();
    if (!pid) {
        printf("Producer here: %d\n", getpid());
        producer();
        printf("Full value after prod() %d\n", sem_get_val(full));
        return 0;
    } else printf("Created new producent: %d\n", pid);

    sleep(1);

    pid = fork();
    if (!pid) {
        printf("Consumer here: %d\n", getpid());
        printf("Full value before cons() %d\n", sem_get_val(full)); //here I always get 0
        consumer();
        return 0;
    } else printf("Created new consumer: %d\n", pid);

       while (1)
    {
        int status;
        pid_t done = wait(&status);
        if (done == -1)
        {
            if (errno == ECHILD) break; // no more child processes
        }
        else
        {
            if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
                exit(1);
            }
        }
    }

    if (getpid() == parent_pid) {
        sem_deallocate(full);
        sem_deallocate(empty);
        sem_deallocate(mutex);
    }
}

void producer() {

    sem_wait(empty);
    sem_wait(mutex);
    printf("Producer is producing!\n");
    buffer->queue[0]=0;
    sem_post(mutex);
    sem_post(full);
}


void consumer() {

    sem_wait(full);
    sem_wait(mutex);
    printf("Consumer is consuming!\n");
    sem_post(mutex);
    sem_post(empty);

}

int sem_allocate() {
    return semget(IPC_PRIVATE, 1, IPC_CREAT | 0666);
}

void sem_deallocate(int semid) {

        if (semctl(semid, 0, IPC_RMID, NULL) == -1)
    {
        perror("Error releasing semaphore!\n");
        exit(EXIT_FAILURE);
    }
}

int sem_init(int semid, int value) {
    union semun arg;
    arg.val = value;
    if (semctl(semid, 0, SETVAL, arg) == -1) {
        perror("semctl");
        return -1;
    }else return 1;
}

int sem_wait(int semid) {
    printf("Someone is waiting %d\n", semid);
    struct sembuf sem = { 0, -1, SEM_UNDO };
    return semop(semid, &sem, 1);
}

int sem_post(int semid) {
    printf("Someone is posting %d\n", semid);
    struct sembuf sem = { 0, 1, SEM_UNDO };
    return semop(semid, &sem, 1);
}

int sem_get_val(int semid) {
    return semctl(semid, 0, GETVAL, 0);
}


int allocate_shared_memory(int size) {
    return shmget(IPC_PRIVATE, size, IPC_CREAT | SHM_W | SHM_R);
}

void deallocate_shared_memory(const void* addr, int shmid) {
    shmctl(shmid, IPC_RMID, 0);
}

void* attach_shared_memory(int shmid) {
    return shmat(shmid, NULL, 0);
}

sem.h中:

#include <sys/types.h>
#include <errno.h>

union semun {
    int val;
    struct semid_ds *buf;
    ushort* array;
};


int sem_post(int);

int sem_wait(int);

int sem_allocate();

void sem_deallocate(int);

int sem_init(int, int);

int sem_get_val(int);

shm.h:

#include <stdio.h>
#include <sys/shm.h>
#include <sys/stat.h> 

int allocate_shared_memory(int size);

void deallocate_shared_memory(const void* addr, int shmid);

void* attach_shared_memory(int shmid);

为什么在执行完整信号量的消费者函数值之前为0?即使生产者完成工作后,价值也是1 ......

我对这类话题很陌生,所以也许会有明显的情况,但我不知道我能做些什么,希望你能帮助我。

1 个答案:

答案 0 :(得分:0)

将“完整”信号量初始化为零。您的“子”生成器在退出之前会调用sem_post()函数,该函数使用semop()参数调用SEM_UNDO

int sem_post(int semid) {
    printf("Someone is posting %d\n", semid);
    struct sembuf sem = { 0, 1, SEM_UNDO };
    return semop(semid, &sem, 1);
}

semop的Ubuntu Linux手册页中有关于SEM_UNDO的以下内容:

  

...如果操作指定SEM_UNDO,它将自动执行   当流程终止时撤消。

这意味着,“生产者”在退出之前增加“满”,然后在退出系统之后“撤消”增量(即减少“满”),将其设置回零。

因此,出于“完整”信号量的目的,您不应指定SEM_UNDO。