【问题标题】:memory efficient way of implementing a circular buffer using mmap使用 mmap 实现循环缓冲区的内存有效方法
【发布时间】:2021-06-14 02:36:10
【问题描述】:

我正在使用 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 指针。

【问题讨论】:

  • 我根本不明白这种方法是如何工作的。您将指针存储在进程共享缓冲区中,但一个进程的指针对其他进程没有意义。即使它们指向映射的内存也不行。
  • 它将分配整个内存页面。共享映射必须页面对齐并且是页面大小的倍数。这里真的没有效率低下。您可能有竞争条件。您没有显示 other 客户端代码,因此它可能会在 sem_init 调用生效之前访问该区域。
  • 正如约翰所说,您不能在共享内存中使用指针。 除非您正在执行fork 然后调用子函数(即它将继承父内存映射)。如果您有 两个 客户端进行类似的设置,正如 John 所提到的,它不会工作。最好计算所有共享数据的总大小并将其映射为一个巨大的区域。您可以将指针替换为从共享区域开始的 [byte] 偏移量。
  • 对不起,我忘了提到我在提到的代码之后使用了 fork。沟通发生在父母和孩子之间。
  • 好的,然后sem_init 上的 no 竞争条件。那么,问题是什么?代码not以什么方式工作?

标签: c ipc shared-memory mmap


【解决方案1】:

您的代码有一些错误。

第二个mmap 调用使用sizeof(N_buff) [这是总是 4] 而不是:sizeof(*shared_data-&gt;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);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-01
    相关资源
    最近更新 更多