使用 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);
}
我正在使用 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);
}