本文介绍了使用mmap()初始化2D数组的共享内存,是否还需要映射内存以供后续指针使用?我应该改用shm吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用mmap()初始化父进程和子进程的共享内存空间,并且该对象恰好是双字符指针(即char**).这是必要的,因为我将在子进程中将用户输入存储到此2D数组,并且子进程终止后,父进程将访问相同的数据.阅读mmap()上的一些文档后,解决这个问题并不难,感觉很像malloc(),但是投入较少.

I am using mmap() to initialize a shared memory space for parent and child processes and the object happens to be a double char pointer (i.e. char**). It's necessary because I'm going to be storing user input to this 2D array in a child process and the parent will be accessing this same data after the child has terminated. It wasn't hard to work this out after reading a little bit of documentation on mmap(), and it feels a lot like malloc(), but less of a commitment.

考虑以下代码,直接从我正在编写的程序中复制以下代码:

Consider the code below, copied directly from the program I'm writing:

/* mmap prot and flags */
int protection = PROT_READ | PROT_WRITE;     // readable and writable
int map_flags  = MAP_SHARED | MAP_ANONYMOUS; // no file, changes are propagated

/* initialize shared memory */
char **histv = (char**)mmap(NULL,              // (void*)  address
                (sizeof(char*) * MAX_HISTORY), // (size_t) length
                protection,                    // (int)    memory protection
                map_flags,                     // (int)    mapping flags
                -1,                            // (int)    file descriptor
                0);                            // (off_t)  addr offset

for (int i = 0; i < MAX_HISTORY; i++) {
    histv[i] = (char*)mmap(NULL,
                (sizeof(char) * MAX_LINE),
                protection,
                map_flags,
                -1,
                0);
}

我的问题:

  1. 我必须遍历指针数组以映射数组中的每个后续地址,还是我真的只需要从第一个映射返回的指针?

  1. Must I loop through the array of pointers to map each subsequent address in the array or do I really only need the pointer returned from the first mapping?

如果不需要,是否仍建议这样做?

If it is not required, is it recommended to do it anyways?

是否有实际原因始终将shm_open()ftruncate()mmap()结合使用而不是使用MAP_ANONYMOUS? (注意:我从未使用过前两个,最近我已经阅读了很多有关共享内存的信息.)

Is there any practical reason to always use shm_open() and ftruncate() in conjunction with mmap() instead of using MAP_ANONYMOUS? (note: I have never used the former two, I've just recently been reading a lot about shared memory.)

推荐答案

首先,char a[N][M]char **a = malloc(...)之间是有区别的.

First, there is a difference between char a[N][M] and char **a = malloc(...).

使用前者,您可以像使用任何其他语言一样将其视为矩阵.

With the former, you can treat it like a matrix as you would in any other language.

对于后者,您将调用malloc(N * sizeof(char *)),即,您将分配N个指针,对于每个这样的指针,您将调用malloc(M * sizeof(char)).

With the latter, you would call malloc(N * sizeof(char *)), i.e. you'd allocate N pointers, and for each such pointer, you'd call malloc(M * sizeof(char)).

如果您想一次完成所有分配,则可以调用malloc(N * (sizeof(char *) + M * sizeof(char))),即您将为N个大小为M的char数组和一个char *数组分配足够的内存.

If you wanted to do all the allocations in one go, you'd call malloc(N * (sizeof(char *) + M * sizeof(char))), i.e. you'd malloc enough memory for N char arrays of size M, plus one char * array.

所有这些都适用于任何形式的内存分配,无论是malloc(3)mmap(2)还是其他类型-但是,请参阅以下内容.

All this applies to any form of memory allocation, be it malloc(3), mmap(2), or whatever - However, see the following.

第二,这很重要:

Second, and this is very important:

假定mmap()的要点是与其他进程共享内存,您不能将指针放在映射的内存中.

Assuming that the point of mmap() is to share the memory with other processes, you cannot put pointers in the mmapped memory.

来自一个地址空间(=进程)的指针仅在该地址空间内有效.

Pointers coming from one address space (= process) are only valid within that address space.

要回答您的问题:

  1. 您可以一次调用mmap(),如我上面在malloc()所示,也可以循环调用.但是,如果希望将其视为矩阵,则必须在循环中初始化指针.但是,请不要执行任何操作-参见下文
  2. 建议通常取决于您是否需要新的历史记录条目以及MAX_HISTORY的大小.如果它很大且不经常使用,请一一分配,不要预先分配所有内容.如果它经常使用或很小,则一口气分配.
  3. 人们共享内存时使用shm_open(3)的原因是能够在内存上附加一个名称,从而允许其他进程仅按名称访问它. ftruncate(2)通常用于设置文件大小,因为如果文件小于您要映射的大小,则mmap()不会映射您想要的所有内存.
  1. You could call mmap() in one go, as I showed above with malloc(), or in a loop. However, if you want to be able to treat it as a matrix, you'd have to initialize the pointers in a loop. However, don't do any of those - see below
  2. The recommendation depends on often you need a new history entry, and how big is MAX_HISTORY. If it's big and not often used, allocate one-by-one, don't allocate everything up-front. if it's used often or if it's small, allocate in one go.
  3. The reason people use shm_open(3) when sharing memory is to be able to attach a name to the memory, allowing other processes to just access it by name. ftruncate(2) is generally used to set the file size, because if the file is smaller than the size you're mmapping, mmap() won't map all of the memory you wanted it to.

假设历史可能足够短(可能是这样),您的情况要求如下:

Assuming that the history is small enough, because it probably is, what your case calls for is as follows:

// allocate a matrix in one go
char *histv = (char *)mmap(NULL, // note the type, char * not char **
                (sizeof(char*) * MAX_HISTORY * MAX_LINE), // note the size, no extra array
                protection,
                map_flags,
                -1,
                0);

// manually implement the same logic the C compiler implements for arrays such as a[N][M]
char *history_get(n)
{
    return histv + (n * MAX_LINE);
}

这篇关于使用mmap()初始化2D数组的共享内存,是否还需要映射内存以供后续指针使用?我应该改用shm吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-03 09:14