基于共享内存的生产者消费者模型例子

15 篇文章 0 订阅
// SharedData.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <string.h>
#include <semaphore.h>
#include <time.h>
#include "SharedData.h"

static void cleanup(struct SharedData *sharedData, int shm_fd)
{
    if (sharedData != NULL)
    {
        munmap(sharedData, sizeof(struct SharedData));
    }
    if (shm_fd != -1)
    {
        close(shm_fd);
    }
    sem_close(&sharedData->sem_empty);
    sem_close(&sharedData->sem_full);
    sem_close(&sharedData->sem_response);
}

int InitializeSharedData(struct SharedData **sharedData, char *shmName ,bool creatFlag)
{
    int shm_fd = shm_open(shmName, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
    if (shm_fd == -1)
    {
        perror("shm_open");
        cleanup(NULL, shm_fd);
        return 1;
    }

    if (ftruncate(shm_fd, sizeof(struct SharedData)) == -1)
    {
        perror("ftruncate");
        cleanup(NULL, shm_fd);
        return 2;
    }

    *sharedData = (struct SharedData *)mmap(NULL, sizeof(struct SharedData), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
    if (*sharedData == MAP_FAILED)
    {
        perror("mmap");
        cleanup(*sharedData, shm_fd);
        return 3;
    }

    if (creatFlag)
    {
        memset(*sharedData, 0, sizeof(struct SharedData));
        // 初始化信号量
        if (sem_init(&(*sharedData)->sem_empty, 1, BUFFER_SIZE) == -1 ||
            sem_init(&(*sharedData)->sem_full, 1, 0) == -1  ||
            sem_init(&(*sharedData)->sem_response, 1, 0) == -1)
        {
            perror("sem_init");
            cleanup(*sharedData, shm_fd);
            return 4;
        }
    }
    else
    {
        int semValue;
        sem_getvalue(&(*sharedData)->sem_empty, &semValue);

        printf("action with sem_empty[%d]\n",semValue);
        return 0;
    }

    return 0;
}

int ProducerEnqueue(struct SharedData *sharedData, const char *data)
{
    struct timespec timeout;

    memset(&timeout, 0, sizeof(timeout));

    sem_wait(&sharedData->sem_empty);
    memcpy(sharedData->buffer[sharedData->in], data, DATA_SIZE);
    sharedData->in = (sharedData->in + 1) % BUFFER_SIZE;
    sem_post(&sharedData->sem_full);

    clock_gettime(CLOCK_REALTIME, &timeout);
    timeout.tv_sec += 1; // 设置超时时间
    if (sem_timedwait(&sharedData->sem_response, &timeout) == -1)
    {
        perror("sem_timedwait");
        return -1;
    }
}

void ConsumerDequeue(struct SharedData *sharedData, char *output)
{
    int semValue = 0;
    sem_wait(&sharedData->sem_full);
    memcpy(output, sharedData->buffer[sharedData->out], DATA_SIZE);
    memcpy(sharedData->response, sharedData->buffer[sharedData->out], DATA_SIZE);
    sharedData->out = (sharedData->out + 1) % BUFFER_SIZE;
    sem_post(&sharedData->sem_empty);

    sem_getvalue(&sharedData->sem_response, &semValue);

    if (!semValue)
    {
        sem_post(&sharedData->sem_response); // 发送回应信号
    }
}

// shared_data.h
#ifndef SHARED_DATA_H
#define SHARED_DATA_H

#include <semaphore.h>
#include <stdbool.h>

#define DATA_SIZE 256
#define BUFFER_SIZE 5

#pragma pack(1)
struct SharedData
{
    char buffer[BUFFER_SIZE][DATA_SIZE]; // 用于存储共享数据
    int in;                   // 指向下一个生产者要写入的位置
    int out;                  // 指向下一个消费者要读取的位置
    char response[DATA_SIZE]; // 用于存储回应的共享内存区域
    sem_t sem_empty;          // 生产者等待缓冲区非满的信号量
    sem_t sem_full;           // 消费者等待缓冲区非空的信号量
    sem_t sem_response;       // 用于同步回应的信号量
};
#pragma pack()

int InitializeSharedData(struct SharedData **sharedData, char *shmName ,bool creatFlag);
int ProducerEnqueue(struct SharedData *sharedData, const char *data);
void ConsumerDequeue(struct SharedData *sharedData, char *output);

#endif // SHARED_DATA_H

// Producer.c
#include <stdio.h>
#include <semaphore.h>
#include "SharedData.h"

#define SHM_NAME "/my_shared_memory"

int main()
{
    struct SharedData *sharedData = NULL;
    int ret = 0;

    if (InitializeSharedData(&sharedData, SHM_NAME, true) != 0)
    {
        return 1;
    }

    // 生产者循环写入数据
    while (1)
    {
        char input[DATA_SIZE];
        memset(input, 0, sizeof(input));

        printf("请输入生产者要生成的数据: ");
        if (fgets(input, DATA_SIZE, stdin) != NULL)
        {
            input[strcspn(input, "\n")] = '\0'; // 去除换行符
        }

        ret = ProducerEnqueue(sharedData, input);
        if (ret)
        {
            // 处理超时的情况,例如报警
            printf("ConsumerDequeue: 超时,没有收到数据\n");
        }

        printf("生产者收到回应: [%s]\n", sharedData->response);
    }

    return 0;
}

// Consumer.c
#include <stdio.h>
#include <semaphore.h>
#include "SharedData.h"

#define SHM_NAME "/my_shared_memory"

int main()
{
    struct SharedData *sharedData = NULL;
    char output[DATA_SIZE];

    if (InitializeSharedData(&sharedData, SHM_NAME, false) != 0)
    {
        return 1;
    }

    // 消费者循环读取数据
    while (1)
    {
        memset(output, 0, sizeof(output));
        ConsumerDequeue(sharedData, output);
        printf("消费者读取: [%s]\n", output);
    }

    return 0;
}

  • 因为将无名信号量也放进共享内存中了,所以可使用其进行进程间同步
  • 需要先启动生产者进程
  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值