0

I am trying to share an unordered map(hash map) but it is ending up with the Floating point exception at the line where it tries to insert the data in the map.

Could someone please help in understanding where I am going wrong?

#include <iostream>
#include <string>
#include <unordered_map>

#include <sys/ipc.h>
#include <sys/shm.h>
int main ()
{
    std::unordered_map<std::string,double> *tmp;

    key_t key = 5678;
    int shmid = shmget(key, 1000, IPC_CREAT | IPC_EXCL | 644);
    if(shmid == -1){
        std::cerr << "Failed to create the shared segment." << std::endl;
        exit(-1);
    }

    void *addr = shmat(shmid, NULL, 0);
    if(addr == (void*)-1){
        std::cerr << "Failed to attach the segment to the process." << std::endl;
        exit(-1);
    }

    tmp = static_cast< std::unordered_map<std::string,double>* >(addr);
    tmp->insert (std::pair<std::string,double>("abc",1.2));

    shmdt(addr);
    return 0;
}

Thanks.

mandeep
  • 433
  • 8
  • 17
  • 1
    I don't think that the type std::unordered_map* and void * returned by shmat is related to static_cast work properly. – coelhudo Aug 01 '12 at 14:48

2 Answers2

6

In general, you can't share complex structures between processes. In particular, pointers to objects in the virtual address space of one process won't be valid in another, and most container implementations will involve pointers.

You could look at the Boost.Interprocess library which contains various containers and allocators suitable for sharing; in particular, their version of unordered_map can be placed in shared memory, as long as you use their shared memory allocator, so you might simply be able to use that as a replacement for std::unordered_map (although you'd still need a replacement for std::string as the key).

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • 1
    In theory, custom allocators were supposed to allow this. (In practice, I'm somewhat skeptical.) – James Kanze Aug 01 '12 at 15:11
  • @JamesKanze: Indeed, I'm also skeptical, to the extent of not even suggesting it. You'd be relying on a very conformant implementation of the container, and I wouldn't be surprised if some implementations were to fail if, for example, `pointer` were something other than `T*`. – Mike Seymour Aug 01 '12 at 15:21
  • So is it so complex that it is better to go with some other approach and if that is the case what would be the best option? I want a hash map to be shared across processes. Please suggest something. I am kind of stuck – mandeep Aug 03 '12 at 09:16
  • 1
    @mandeep: As I said in my answer, I suggest [Boost.Interprocess](http://www.boost.org/doc/libs/release/doc/html/interprocess.html); in particular, `boost::unordered_map` using `boost::interprocess::allocator`. If you [follow the second link](http://www.boost.org/doc/libs/release/doc/html/interprocess/allocators_containers.html#interprocess.allocators_containers.additional_containers.unordered) in the answer, you'll see an example of putting a map into shared memory, which should get you started. My comment was referring to writing your own custom allocator; I suggest you don't try that. – Mike Seymour Aug 03 '12 at 10:35
  • If you select a specific base address when you map shared memory, you can share pointers and complex objects all you want. To handle complex objects, we added code to our string class, our array class, our hash class, etc that checks which pool an object is allocated in and continues to allocate memory in that pool. Since we quantized our memory pools sizes to multiples of 4GB, a pool is found from an address by shifting the address right by 32. – johnnycrash May 19 '14 at 16:32
1

You are casting your shared memory address to a pointer to a map, but you never call the constructor to actually create a map at that address. This is likely not going to work the way you want, anyway, since the map may allocate and deallocate memory for it's own use that will come from the heap, not from your shared memory area.

twalberg
  • 59,951
  • 11
  • 89
  • 84