Search code examples
c++forkshared-memoryprocess-management

C++ - Forked Process Can't Read from Shared Memory


I'm learning about process management and shared memory, and I was wondering if someone could help me out. I'm trying to read in a large-ish text file (2MB) with a forked parent process and feed it to the corresponding child process to be ... well ... processed. However, my proof of concept mini program cannot READ the data I write into the shared memory. Calling 'capacity()' and 'length()' work fine, but actually attempting to retrieve the data stored there returns an empty string. I even tried copying the contents from the pointer into an array of characters, but still nothing. Any thoughts?

Program code:

#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

using namespace std;

#define SHM_SIZE 2000000    // 2 MB of shared memory

int main(int argc, char* argv[])
{
    string* data = (string*) mmap(NULL, SHM_SIZE, PROT_READ | PROT_WRITE, 
    MAP_SHARED | MAP_ANONYMOUS, -1, 0);

printf("Shared memory capacity before reserve: %ld\n", data->capacity());
data->reserve(SHM_SIZE); // make sure string can use all available space
printf("Shared memory capacity after reserve: %ld\n", data->capacity());

switch(fork())
{
    case -1:
        printf("Something went wrong ... exiting program\n");
        break;
    case 0:
        usleep(1000 * 1000 * 2); // force child to wait for sanity purposes
        printf("\nChild capacity:  %ld\n", data->capacity());
        printf("Child contents:  %s\n", data->c_str());
        break;
    default:
        // Sample input ... file reading logic omitted for brevity
        *data = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean leo elit, aliquam "
            "vitae aliquam sed, rhoncus et mi. Aliquam erat volutpat. Phasellus non urna sit amet "
            "enim tincidunt aliquam quis sit amet orci. Maecenas velit turpis, venenatis eu diam "
            "vel, varius volutpat nulla. Nam mi massa, tristique eget imperdiet id, dictum ut urna. "
            "Nulla id massa placerat, finibus purus quis, ornare neque. Vivamus eget varius ante. "
            "Aenean varius ac neque quis ultricies. Donec vitae bibendum dolor, vitae tempor augue.";
        printf("\nParent capacity:  %ld\n", data->capacity());
        printf("Parent contents:  %s\n", data->c_str());

        wait(NULL);
        munmap(data, sizeof *data);
        printf("\nHello world\n");
        break;
}

return 0;
}

Output:

MacBook-Pro:sharedmem-test slehr$ ./sharedmem-mapred 
Shared memory capacity before reserve: 22
Shared memory capacity after reserve: 2000015

Parent capacity:  2000015
Parent contents:  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean leo elit, aliquam vitae aliquam sed, rhoncus et mi. Aliquam erat volutpat. Phasellus non urna sit amet enim tincidunt aliquam quis sit amet orci. Maecenas velit turpis, venenatis eu diam vel, varius volutpat nulla. Nam mi massa, tristique eget imperdiet id, dictum ut urna. Nulla id massa placerat, finibus purus quis, ornare neque. Vivamus eget varius ante. Aenean varius ac neque quis ultricies. Donec vitae bibendum dolor, vitae tempor augue.

Child capacity:  2000015
Child contents:  

Hello world
MacBook-Pro:sharedmem-test slehr$ 

Solution

  • A std::string is likely to be some data structure with a size, a length, a pointer (or something similar). You can't expect its internal pointer to point to shared memory

    with mmap-ed memory you should use raw pointers, e.g.

    auto data = (char*) mmap(NULL, SHM_SIZE, PROT_READ | PROT_WRITE, 
                             MAP_SHARED | MAP_ANONYMOUS, -1, 0);
    

    Of course you should test against failure:

    if (data==(char*)MAP_FAILED) { perror("mmap"); exit(EXIT_FAILURE); };
    

    Read again mmap(2)

    You might consider shm_overview(7) (and look at sem_oveview(7) for synchronization)

    Read Advanced Linux Programming