使用 mmap 实现循环缓冲区的内存有效方法

memory efficient way of implementing a circular buffer using mmap

我正在使用 mmap 使用共享内存实现 IPC。我用于分享的结构是

struct shared{
    sem_t P;
    sem_t C;
    sem_t M;
    int prod_status;
    char** queue;
    int buffer_size;
    int queue_start;
    int queue_after_last;       //pointing to buffer index after the last element in the buffer
    int queue_count;
};

缓冲区的大小作为命令行参数传递。

int main(int agrc, char* argv[]){
    int N_buff=atoi(argv[1]);
    struct shared* shared_data=(struct shared*)mmap(NULL,sizeof(struct shared),PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0);
    //printf("hello\n");
    shared_data->buffer_size=N_buff;
    shared_data->queue=(char**)mmap(NULL,sizeof(N_buff),PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0);
    for(int i=0;i<N_buff;i++){
        shared_data->queue[i]=(char*)mmap(NULL,70*sizeof(char),PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0);
    }
    shared_data->queue_start=0;
    shared_data->queue_after_last=0;
    shared_data->queue_count=0;
    shared_data->prod_status=1;
    sem_init(&shared_data->P,1,N_buff);
    sem_init(&shared_data->C,1,0);
    sem_init(&shared_data->M,1,1);};

队列被其他进程访问。我正在使用队列作为管道。 问题是,每次我使用

分配内存
shared_data->queue[i]=(char*)mmap(NULL,70*sizeof(char),PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0);

它将分配整页内存。有没有其他内存有效的方法来使用 mmap 实现这个? 我在这段代码之后使用 fork 来生成子进程,所以我想我可以使用这种方法在父子进程之间使用 IPC 指针。

您的代码有一些错误。

第二个 mmap 调用使用了 sizeof(N_buff) [即 always 4] 而不是:sizeof(*shared_data->queue) * N_buff

可以对所有数据执行单个 mmap [见下文]。


这是带注释和更正的代码:

#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <sys/sem.h>
#include <sys/mman.h>

struct shared {
    sem_t P;
    sem_t C;
    sem_t M;
    int prod_status;
    char **queue;
    int buffer_size;
    int queue_start;
    // pointing to buffer index after the last element in the buffer
    int queue_after_last;
    int queue_count;
};

int
main(int agrc, char *argv[])
{
    int N_buff = atoi(argv[1]);
    struct shared *shared_data;

    shared_data = mmap(NULL, sizeof(struct shared), PROT_READ | PROT_WRITE,
        MAP_SHARED | MAP_ANONYMOUS, -1, 0);

    // printf("hello\n");
    shared_data->buffer_size = N_buff;
// NOTE/BUG: sizeof(N_buff) is _always_ 4
#if 0
    shared_data->queue = mmap(NULL, sizeof(N_buff), PROT_READ | PROT_WRITE,
        MAP_SHARED | MAP_ANONYMOUS, -1, 0);
#else
    shared_data->queue = mmap(NULL, sizeof(*shared_data->queue) * N_buff,
        PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
#endif
// NOTE: sizeof(char) is _always_ 1
    for (int i = 0; i < N_buff; i++) {
        shared_data->queue[i] = mmap(NULL, 70,
            PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
    }

    shared_data->queue_start = 0;
    shared_data->queue_after_last = 0;
    shared_data->queue_count = 0;
    shared_data->prod_status = 1;

    sem_init(&shared_data->P, 1, N_buff);
    sem_init(&shared_data->C, 1, 0);
    sem_init(&shared_data->M, 1, 1);
}

这里是 单个 mmap 的一些清理代码 [我已经编译但 没有 测试它]:

#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <sys/sem.h>
#include <sys/mman.h>

#define PERQUEUE 70

struct shared {
    sem_t P;
    sem_t C;
    sem_t M;
    int prod_status;
    char **queue;
    int buffer_size;
    int queue_start;
    // pointing to buffer index after the last element in the buffer
    int queue_after_last;
    int queue_count;
};

int
main(int agrc, char *argv[])
{
    int N_buff = atoi(argv[1]);
    struct shared *shared_data = NULL;
    size_t total_size = 0;

    total_size += sizeof(struct shared);
    total_size += sizeof(*shared_data->queue) * N_buff;
    total_size += sizeof(PERQUEUE * N_buff);

    void *mapbase = mmap(NULL, total_size, PROT_READ | PROT_WRITE,
        MAP_SHARED | MAP_ANONYMOUS, -1, 0);

    void *mapcur = mapbase;

    shared_data = mapcur;
    mapcur += sizeof(struct shared);

    // printf("hello\n");
    shared_data->buffer_size = N_buff;

    shared_data->queue = mapcur;
    mapcur += sizeof(*shared_data->queue) * N_buff;

    for (int i = 0; i < N_buff; i++) {
        shared_data->queue[i] = mapcur;
        mapcur += PERQUEUE;
    }

    shared_data->queue_start = 0;
    shared_data->queue_after_last = 0;
    shared_data->queue_count = 0;
    shared_data->prod_status = 1;

    sem_init(&shared_data->P, 1, N_buff);
    sem_init(&shared_data->C, 1, 0);
    sem_init(&shared_data->M, 1, 1);

    // stuff ...

    munmap(mapbase,total_size);
}