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

标签 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);

为什么在执行consumer函数之前full semaphore的值为0?即使生产者完成工作后该值是 1...

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

最佳答案

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

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 做了如下说明:

... If an operation specifies SEM_UNDO, it will be automatically undone when the process terminates.

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

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

关于c - 生产者消费者信号量值不正确,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47664635/

相关文章:

c - 提取 C 二进制文件中的 _fini

grails - Grails的后台进程插件

process - 如何通过 session 结束时不终止的 ssh 启动进程?

operating-system - 修改为 "Implementing an N process barrier using semaphores"

c++ - 在 Qt 的子线程中调用函数?

c++ - 如何在 x86 和 x64 中对函数进行 thunk? (类似于 C++ 中的 std::bind,但是是动态的)

c - 显示访问文件夹的进程

c++ - memcmp 排序

algorithm - 查找进程的执行顺序

c - futex 工具返回了意外的错误代码并中止