Initializing shared memory using mmap() for a 2D array, is it necessary to also map memory for subsequent pointers? Should I use shm instead?

元气小坏坏 提交于 2021-01-29 08:48:51

问题


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);
}

My questions:

  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?

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

  3. 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.)


回答1:


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.

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)).

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.

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:

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.

To answer your questions:

  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);
}


来源:https://stackoverflow.com/questions/59222268/initializing-shared-memory-using-mmap-for-a-2d-array-is-it-necessary-to-also

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!