7

I am trying to create an unordered_map in shared memory. I am using allocator to server the purpose.

The code

void *addr;
void *pool;
int shmid;

template<class T>
class MyPoolAlloc {
private:
public:
    typedef size_t     size_type;
    typedef ptrdiff_t  difference_type;
    typedef T*         pointer;
    typedef const T*   const_pointer;
    typedef T&         reference;
    typedef const T&   const_reference;
    typedef T          value_type;

   template<class X>
   struct rebind
   { typedef MyPoolAlloc<X> other; };

   MyPoolAlloc() throw() {
   }
   MyPoolAlloc(const MyPoolAlloc&) throw()  {
   }

   template<class X>
   MyPoolAlloc(const MyPoolAlloc<X>&) throw() {
   }

   ~MyPoolAlloc() throw() {
   }

  pointer address(reference __x) const { return &__x; }

  const_pointer address(const_reference __x) const { return &__x; }

  pointer allocate(size_type __n, const void * hint = 0) {
      pointer tmp = static_cast<T*>(addr);
      addr = (void*)((char*)addr + __n);
      return tmp;
  }

  void deallocate(pointer __p, size_type __n) {
      // pMyPool->Free(reinterpret_cast<void *>(__p));
  }

 size_type max_size() const throw() {
    //return size_t(-1) / sizeof(T);
  }

 void construct(pointer __p, const T& __val) {
     ::new(__p) T(__val);
  }

 void destroy(pointer __p) {
    //__p->~T();
  }
};

typedef std::unordered_map<int, int, std::hash<int>, std::equal_to<int>,  MyPoolAlloc<std::pair<const int,int>> > Map;

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

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

    Map *m = new(pool) Map;

    m->insert(std::pair<int, int>(2,4));

    shmdt(addr);
    shmctl(shmid, IPC_RMID, 0);

    return 0;
}

I am allocating memory for the map on shared memory address. And I suppose for the elements the allocator class' allocate() function will be used. But I am not able to figure out how to use allocate function to allocate memory for the elements of the map. I am getting Arithmetic Exception at the line where I am trying to insert in the map.

Could someone please help to understand how the memory layout should be?

Thanks.

B Faley
  • 17,120
  • 43
  • 133
  • 223
mandeep
  • 433
  • 8
  • 17
  • 1
    I've written some data structure code (hash table, AVL tree) which provides an abstaction of "links" and allows you to use something else instead of pointers (e.g. array indices within an array of all entries). It may help you greatly here. See http://code.google.com/p/slib/wiki/GenericDataStructures_Introduction – Ambroz Bizjak Aug 07 '12 at 09:43
  • It's not completely abstracted though; for example the hash table object still does malloc() to build the buckets array (as opposed to entry data), and stores a pointer to this array, so you should be careful. – Ambroz Bizjak Aug 07 '12 at 09:44

1 Answers1

7

As I said last time you asked about this, you can't store pointers in shared memory and expect them to be usable in more than one process. As before, I suggest using boost::unordered_map in conjunction with boost::interprocess::allocator.

If you really want to write your own allocator, you'll need some kind of custom pointer that stores the offset into the shared memory block, and is able to reconstruct the correct address from that. I wouldn't recommend trying to do this yourself: as well as it being quite fiddly, you may find that some implementations of std::unordered_map don't work correctly with unconventional pointer types. In fact, I suspect that it might be impossible to make a standard-compliant allocator for shared memory; otherwise, the Boost allocator would surely be usable by all standard containers, not just special Boost versions.

By the way, you shouldn't use reserved names like __p (containing a double underscore) in your own code; they should only be used by the Standard Library implementation.

Community
  • 1
  • 1
Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • Hey Mike, I just wanted to give it a try before jumping to the boost interprocess impl but not getting enough information on this. – mandeep Aug 07 '12 at 09:06
  • @mandeep: Fair enough. I'm guessing that it's not possible to write a standard-compliant allocator for shared memory; otherwise the Boost allocator would be usable with standard containers, not just special Boost versions. Perhaps they missed something, though. – Mike Seymour Aug 07 '12 at 10:22
  • 1
    Jumping in late here. This is a line from the MSVC xtree.h file (defines the base classes for `map`, `set` etc.): `typedef _Node *_Nodeptr; // _Node allocator must have ordinary pointers` – Anthony May 31 '13 at 00:17
  • 1
    You can store pointers in shared memory if you select the same value for your base address in each process. – johnnycrash May 19 '14 at 16:23