问题
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:
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?
Is there any practical reason to always use
shm_open()
andftruncate()
in conjunction withmmap()
instead of usingMAP_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:
- You could call
mmap()
in one go, as I showed above withmalloc()
, 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 - 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. - 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