Question

I have the classic problem as given here, here and here and also here,

However, I would like a child process to insert an element at the end of a doubly linked list. a point to the first element of the list is global, and I want to access all of the list elements form the main process, and also next time I branch the main using fork, I want to be abe to access all elements, and update them, and insert more elements, in turn the main process again being able to access the modifyied list.

Each process exits with a system call with execvp (i need them to be able to call stuff using varied number of arameters).

I perhaps am asking a too broad question, but I personally did not get any further than branching and the inserting an element at the end of the list. Thus I actually dont have a single line of code that takes me where I want to go. I have no idea how to use shm() in this scenario.

Please help.

Was it helpful?

Solution

You can try this.. I just wrote it from scratch.. It is cross-platform so that's always a plus. The allocators and pools can be re-used with anything. For example, you can make any stl container allocate on the stack or wherever you want..

SharedMemory.hpp:

#ifndef SHAREDMEMORY_HPP_INCLUDED
#define SHAREDMEMORY_HPP_INCLUDED

#if defined _WIN32 || defined _WIN64
    #include <windows.h>
#else
    #include <sys/types.h>
    #include <sys/mman.h>
    #include <dlfcn.h>
    #include <fcntl.h>
    #include <unistd.h>
#endif

#include <string>
#include <cstdint>

class SharedMemory
{
    private:
        std::string name;
        std::size_t size;
        void* data;
        void* hFileMap;

    public:
        SharedMemory(std::string name, std::size_t size) : name(name), size(size), data(nullptr), hFileMap(nullptr) {};
        ~SharedMemory();

        bool Open();
        bool Create();

        std::size_t GetSize() const {return this->size;}
        void* GetPointer() const {return this->data;}
};

#endif // SHAREDMEMORY_HPP_INCLUDED

SharedMemory.cpp:

#include "SharedMemory.hpp"

SharedMemory::~SharedMemory()
{
    if (data)
    {
        #if defined _WIN32 || defined _WIN64
        UnmapViewOfFile(data);
        data = nullptr;

        if (hFileMap)
        {
            if (CloseHandle(hFileMap))
            {
                hFileMap = nullptr;
            }
        }

        #else

        if (data)
        {
            munmap(data, size);
            data = nullptr;
        }

        if (hFileMap)
        {
            if (!close(hFileMap))
            {
                hFileMap = nullptr;
            }
        }
        #endif
    }
}

bool SharedMemory::Open()
{
    #if defined _WIN32 || defined _WIN64
        if ((hFileMap = OpenFileMapping(FILE_MAP_ALL_ACCESS, false, name.c_str())) == nullptr)
        {
            return false;
        }

        if ((data = MapViewOfFile(hFileMap, FILE_MAP_ALL_ACCESS, 0, 0, size)) == nullptr)
        {
            CloseHandle(hFileMap);
            return false;
        }
    #else

        if ((hFileMap = open(MapName.c_str(), O_RDWR | O_CREAT, 438)) == -1)
        {
            return false;
        }

        if ((data = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, hFileMap, 0)) == MAP_FAILED)
        {
            close(hFileMap);
            return false;
        }
    #endif
    return true;
}

bool SharedMemory::Create()
{
    #if defined _WIN32 || defined _WIN64
        if ((hFileMap = CreateFileMapping(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, size, name.c_str())) == nullptr)
        {
            return false;
        }

        if ((data = MapViewOfFile(hFileMap, FILE_MAP_ALL_ACCESS, 0, 0, size)) == nullptr)
        {
            CloseHandle(hFileMap);
            return false;
        }

    #else

        if ((hFileMap = open(MapName.c_str(), O_RDWR | O_CREAT, 438)) == -1)
        {
            return false;
        }

        if ((data = mmap(nullptr, Size, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, hFileMap, 0)) == MAP_FAILED)
        {
            close(hFileMap);
            return false;
        }
    #endif
    return true;
}

Pools.hpp:

#ifndef POOLS_HPP_INCLUDED
#define POOLS_HPP_INCLUDED

#include <stdexcept>
#include <cstdint>
#include "SharedMemory.hpp"

template<typename T>
class SharedPool
{
    private:
        T* data;
        SharedMemory* shm;
        std::size_t size;

    public:
        SharedPool(SharedMemory* shm) : data(reinterpret_cast<T*>(shm->GetPointer())), shm(shm), size(shm->GetSize()) {};

        template<typename U = T>
        void* allocate(std::size_t n, const void* hint = 0) {return &data[0];}

        template<typename U = T>
        void deallocate(U* ptr, std::size_t n) {}

        template<typename U = T>
        std::size_t max_size() const {return size;}
};

#endif // POOLS_HPP_INCLUDED

main.cpp (adding values to shared memory from process one):

#include "SharedMemory.hpp"
#include "Allocators.hpp"
#include "Pools.hpp"

#include <vector>
#include <iostream>

int main()
{
    SharedMemory mem = SharedMemory("Local\\Test_Shared_Memory", 1024);
    if (!mem.Open() && !mem.Create())
    {
        throw std::runtime_error("Error Mapping Shared Memory!");
    }

    auto pool = PoolAllocator<int, SharedPool<int>>(SharedPool<int>(&mem));
    std::vector<int, decltype(pool)> v(pool);

    int* ptr = reinterpret_cast<int*>(mem.GetPointer());
    std::cout<<"Pushing 3 values to: "<<ptr<<"\n";

    v.push_back(100);
    v.push_back(200);
    v.push_back(700);

    std::cin.get();
}

main.cpp (Reading values from shared memory process two):

#include "SharedMemory.hpp"
#include "Allocators.hpp"
#include "Pools.hpp"

#include <vector>
#include <iostream>

int main()
{
    SharedMemory mem = SharedMemory("Local\\Test_Shared_Memory", 1024);
    if (!mem.Open() && !mem.Create())
    {
        throw std::runtime_error("Error Mapping Shared Memory!");
    }

    auto pool = PoolAllocator<int, SharedPool<int>>(SharedPool<int>(&mem));
    std::vector<int, decltype(pool)> v(pool);

    int* ptr = reinterpret_cast<int*>(mem.GetPointer());
    std::cout<<"Reading 3 values from: "<<ptr<<"\n";

    v.reserve(3);
    std::cout<<v[0]<<"\n";
    std::cout<<v[1]<<"\n";
    std::cout<<v[2]<<"\n";

    std::cin.get();
}

OTHER TIPS

This is a tough problem.

One way is to use Shared Memory and when you build the linked list, give it your own allocator, to use the shared memory. Other way is to implement your own linked list based on the shared memory.

You can also try to use boost - Boost interprocess, which is probably the ideal solution.

Specifically speaking - interprocess with containers

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top